1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| =======================gen_server========== start_link(Name, Mod, Args, Options) -> gen:start(?MODULE, link, Name, Mod, Args, Options). init_it(Starter, Parent, Name0, Mod, Args, Options) -> Name = gen:name(Name0), Debug = gen:debug_options(Name, Options), HibernateAfterTimeout = gen:hibernate_after(Options),
case init_it(Mod, Args) of {ok, {ok, State}} -> proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug); {ok, {ok, State, TimeoutHibernateOrContinue}} -> proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, State, Mod, TimeoutHibernateOrContinue, HibernateAfterTimeout, Debug); {ok, {stop, Reason}} -> %% For consistency, we must make sure that the %% registered name (if any) is unregistered before %% the parent process is notified about the failure. %% (Otherwise, the parent process could get %% an 'already_started' error if it immediately %% tried starting the process again.) gen:unregister_name(Name0), proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); {ok, ignore} -> gen:unregister_name(Name0), proc_lib:init_ack(Starter, ignore), exit(normal); {ok, Else} -> Error = {bad_return_value, Else}, proc_lib:init_ack(Starter, {error, Error}), exit(Error); {'EXIT', Class, Reason, Stacktrace} -> gen:unregister_name(Name0), proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}), erlang:raise(Class, Reason, Stacktrace) end.
=========================gen============== start(GenMod, LinkP, Name, Mod, Args, Options) -> case where(Name) of undefined -> do_spawn(GenMod, LinkP, Name, Mod, Args, Options); Pid -> {error, {already_started, Pid}} end.
do_spawn(GenMod, link, Name, Mod, Args, Options) -> Time = timeout(Options), proc_lib:start_link(?MODULE, init_it, [GenMod, self(), self(), Name, Mod, Args, Options], Time, spawn_opts(Options));
init_it(GenMod, Starter, Parent, Mod, Args, Options) -> init_it2(GenMod, Starter, Parent, self(), Mod, Args, Options).
init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) -> case register_name(Name) of true -> init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options); {false, Pid} -> proc_lib:init_ack(Starter, {error, {already_started, Pid}}) end.
init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) -> GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).
=========================proc_lib================== start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) -> ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts), sync_start_link(?MODULE:spawn_opt(M, F, A, [link|SpawnOpts]), Timeout). -define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts), case lists:member(monitor, Opts) of true -> erlang:error(badarg, [M,F,A,T,Opts]); false -> ok end).
sync_start_link(Pid, Timeout) -> receive {ack, Pid, Return} -> Return; {'EXIT', Pid, Reason} -> {error, Reason} after Timeout -> kill_flush(Pid), {error, timeout} end.
spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) -> Parent = get_my_name(), Ancestors = get_ancestors(), erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], Opts).
init_p(Parent, Ancestors, M, F, A) when is_atom(M), is_atom(F), is_list(A) -> put('$ancestors', [Parent|Ancestors]), put('$initial_call', trans_init(M, F, A)), init_p_do_apply(M, F, A).
init_p_do_apply(M, F, A) -> try apply(M, F, A) catch Class:Reason:Stacktrace -> exit_p(Class, Reason, Stacktrace) end.
|