|
|
@ -111,10 +111,19 @@ |
|
|
|
|
|
|
|
-type requestId() :: term(). |
|
|
|
|
|
|
|
-record(handler, {module :: atom(), |
|
|
|
-record(handler, { |
|
|
|
module :: atom(), |
|
|
|
id = false, |
|
|
|
state, |
|
|
|
supervised = false :: 'false' | pid()}). |
|
|
|
supervised = false :: 'false' | pid() |
|
|
|
}). |
|
|
|
|
|
|
|
-record(epmHer, { |
|
|
|
epmId = undefined :: term(), |
|
|
|
epmM :: atom(), |
|
|
|
epmSup = undefined :: 'undefined' | pid(), |
|
|
|
epmS :: term() |
|
|
|
}). |
|
|
|
|
|
|
|
-callback init(InitArgs :: term()) -> |
|
|
|
{ok, State :: term()} | |
|
|
@ -221,7 +230,7 @@ init_it(Starter, Parent, ServerRef, _, _, Options) -> |
|
|
|
Debug = gen:debug_options(Name, Options), |
|
|
|
HibernateAfterTimeout = gen:hibernate_after(Options), |
|
|
|
proc_lib:init_ack(Starter, {ok, self()}), |
|
|
|
receiveIng(Parent, Name, [], HibernateAfterTimeout, Debug, false). |
|
|
|
receiveIng(Parent, Name, HibernateAfterTimeout, #{}, Debug, false). |
|
|
|
|
|
|
|
-spec add_epm(serverRef(), epmHandler(), term()) -> term(). |
|
|
|
add_epm(EpmSrv, EpmHandler, Args) -> |
|
|
@ -316,90 +325,391 @@ epmRequest(EpmSrv, Cmd) -> |
|
|
|
EpmSrv ! Cmd, |
|
|
|
ok. |
|
|
|
|
|
|
|
loopEntry(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) -> |
|
|
|
proc_lib:hibernate(?MODULE, wake_hib, [Parent, ServerName, MSL, HibernateAfterTimeout, Debug]); |
|
|
|
loopEntry(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, _) -> |
|
|
|
receiveIng(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, false). |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, true) -> |
|
|
|
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug]); |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, _) -> |
|
|
|
receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, false). |
|
|
|
|
|
|
|
wakeupFromHib(Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> |
|
|
|
receiveIng(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true). |
|
|
|
wakeupFromHib(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug) -> |
|
|
|
receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, true). |
|
|
|
|
|
|
|
receiveIng(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, IsHib) -> |
|
|
|
receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, IsHib) -> |
|
|
|
receive |
|
|
|
{system, From, Req} -> |
|
|
|
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, [ServerName, MSL, HibernateAfterTimeout, IsHib], IsHib); |
|
|
|
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, [ServerName, HibernateAfterTimeout, EpmHers, IsHib], IsHib); |
|
|
|
{'EXIT', Parent, Reason} -> |
|
|
|
terminate_server(Reason, Parent, MSL, ServerName); |
|
|
|
terminate_server(Reason, Parent, ServerName, EpmHers); |
|
|
|
{'$epm_call', From, Request} -> |
|
|
|
epmCallMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, From, Request); |
|
|
|
{'$epm_info', CmdOrEmpHandler, Event} -> |
|
|
|
epmInfoMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, CmdOrEmpHandler, Event); |
|
|
|
Msg -> |
|
|
|
handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug) |
|
|
|
handleMsg(Parent, ServerName, HibernateAfterTimeout,EpmHers, Debug, Msg) |
|
|
|
after HibernateAfterTimeout -> |
|
|
|
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, ServerName, MSL, HibernateAfterTimeout, Debug]) |
|
|
|
proc_lib:hibernate(?MODULE, wakeupFromHib, [Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug]) |
|
|
|
end. |
|
|
|
|
|
|
|
epmCallMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, From, Request) -> |
|
|
|
NewDebug = ?SYS_DEBUG(Debug, ServerName, {call, From, Request}), |
|
|
|
case Request of |
|
|
|
'$which_handlers' -> |
|
|
|
reply(From, EpmHers), |
|
|
|
receiveIng(Parent, ServerName, HibernateAfterTimeout, EpmHers, NewDebug, false); |
|
|
|
{'$addEpm', EpmHandler, Args} -> |
|
|
|
{Reply, NewEpmHers, IsHib} = doAddEpm(EpmHers, EpmHandler, Args, undefined), |
|
|
|
reply(From, Reply), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
{'$addSupEpm', EpmHandler, Args, EpmSup} -> |
|
|
|
{Reply, NewEpmHers, IsHib} = doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup), |
|
|
|
reply(From, Reply), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
{'$deleteEpm', EpmHandler, Args} -> |
|
|
|
{Reply, NewEpmHers} = doDeleteEpm(EpmHers, EpmHandler, Args), |
|
|
|
reply(From, Reply), |
|
|
|
receiveIng(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, false); |
|
|
|
{'$swapEpm', EpmId1, Args1, EpmId2, Args2} -> |
|
|
|
{Reply, NewEpmHers, IsHib} = doSwapEpm(EpmHers, EpmId1, Args1, EpmId2, Args2), |
|
|
|
reply(From, Reply), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
{'$swapSupEpm', EpmId1, Args1, EpmId2, Args2, SupPid} -> |
|
|
|
{Reply, NewEpmHers, IsHib} = doSwapSupEpm(EpmHers, EpmId1, Args1, EpmId2, Args2, SupPid), |
|
|
|
reply(From, Reply), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
{'$syncNotify', Event} -> |
|
|
|
{NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false), |
|
|
|
reply(From, ok), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
{'$epmCall', EpmHandler, Query} -> |
|
|
|
{NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, handleCall, Query, From), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib) |
|
|
|
end. |
|
|
|
|
|
|
|
epmInfoMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, CmdOrEmpHandler, Event) -> |
|
|
|
NewDebug = ?SYS_DEBUG(Debug, ServerName, {info, CmdOrEmpHandler, Event}), |
|
|
|
case CmdOrEmpHandler of |
|
|
|
'$infoNotify' -> |
|
|
|
{NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib); |
|
|
|
EpmHandler -> |
|
|
|
{NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, handleInfo, Event, false), |
|
|
|
loopEntry(Parent, ServerName, HibernateAfterTimeout, NewEpmHers, NewDebug, IsHib) |
|
|
|
end. |
|
|
|
|
|
|
|
handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> |
|
|
|
handleMsg(Parent, ServerName, HibernateAfterTimeout, EpmHers, Debug, Msg) -> |
|
|
|
NewDebug = ?SYS_DEBUG(Debug, ServerName, {in, Msg}), |
|
|
|
case Msg of |
|
|
|
{notify, Event} -> |
|
|
|
{Hib, MSL1} = server_notify(Event, handle_event, MSL, ServerName), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, {sync_notify, Event}} -> |
|
|
|
{Hib, MSL1} = server_notify(Event, handle_event, MSL, ServerName), |
|
|
|
reply(Tag, ok), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{'EXIT', From, Reason} -> |
|
|
|
MSL1 = handle_exit(From, Reason, MSL, ServerName), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, false); |
|
|
|
{_From, Tag, {call, Handler, Query}} -> |
|
|
|
{Hib, Reply, MSL1} = server_call(Handler, Query, MSL, ServerName), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, {add_handler, Handler, Args}} -> |
|
|
|
{Hib, Reply, MSL1} = server_add_handler(Handler, Args, MSL), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, {add_sup_handler, Handler, Args, SupP}} -> |
|
|
|
{Hib, Reply, MSL1} = server_add_sup_handler(Handler, Args, MSL, SupP), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, {delete_handler, Handler, Args}} -> |
|
|
|
{Reply, MSL1} = server_delete_handler(Handler, Args, MSL, |
|
|
|
ServerName), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, false); |
|
|
|
{_From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} -> |
|
|
|
{Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, |
|
|
|
Args2, MSL, ServerName), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2, |
|
|
|
Sup}} -> |
|
|
|
{Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2, |
|
|
|
Args2, MSL, Sup, ServerName), |
|
|
|
reply(Tag, Reply), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib); |
|
|
|
{_From, Tag, stop} -> |
|
|
|
catch terminate_server(normal, Parent, MSL, ServerName), |
|
|
|
reply(Tag, ok); |
|
|
|
{_From, Tag, which_handlers} -> |
|
|
|
reply(Tag, the_handlers(MSL)), |
|
|
|
loopEntry(Parent, ServerName, MSL, HibernateAfterTimeout, NewDebug, false); |
|
|
|
{_From, Tag, get_modules} -> |
|
|
|
reply(Tag, get_modules(MSL)), |
|
|
|
loopEntry(Parent, ServerName, MSL, HibernateAfterTimeout, NewDebug, false); |
|
|
|
{Hib, MSL1} = doNotify(EpmHers, handleInfo, Msg, false), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib). |
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
|
%% EPM inner fun |
|
|
|
addNewEpm(InitRet, EpmHers, Module, EpmId, EpmSup) -> |
|
|
|
case InitRet of |
|
|
|
{ok, State} -> |
|
|
|
EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup}, |
|
|
|
{ok, EpmHers#{EpmId => EpmHer}, false}; |
|
|
|
{ok, State, hibernate} -> |
|
|
|
EpmHer = #epmHer{epmId = EpmId, epmM = Module, epmS = State, epmSup = EpmSup}, |
|
|
|
{ok, EpmHers#{EpmId => EpmHer}, true}; |
|
|
|
Other -> |
|
|
|
{Hib, MSL1} = server_notify(Other, handle_info, MSL, ServerName), |
|
|
|
loopEntry(Parent, ServerName, MSL1, HibernateAfterTimeout, NewDebug, Hib) |
|
|
|
{Other, EpmHers, false} |
|
|
|
end. |
|
|
|
|
|
|
|
terminate_server(Reason, Parent, MSL, ServerName) -> |
|
|
|
stop_handlers(MSL, ServerName), |
|
|
|
do_unlink(Parent, MSL), |
|
|
|
exit(Reason). |
|
|
|
doAddEpm(EpmHers, {Module, _SubId} = EpmId, Args, EpmSup) -> |
|
|
|
case EpmHers of |
|
|
|
#{EpmId := _EpmHer} -> |
|
|
|
{{error, existed}, EpmHers, false}; |
|
|
|
_ -> |
|
|
|
try Module:init(Args) of |
|
|
|
Result -> |
|
|
|
addNewEpm(Result, EpmHers, Module, EpmId, EpmSup) |
|
|
|
catch |
|
|
|
throw:Ret -> |
|
|
|
addNewEpm(Ret, EpmHers, Module, EpmId, EpmSup); |
|
|
|
C:R -> |
|
|
|
{{error, {C, R, ?STACKTRACE()}}, EpmHers, false} |
|
|
|
end |
|
|
|
end; |
|
|
|
doAddEpm(EpmHers, Module, Args, EpmSup) -> |
|
|
|
case EpmHers of |
|
|
|
#{Module := _EpmHer} -> |
|
|
|
{{error, existed}, EpmHers, false}; |
|
|
|
_ -> |
|
|
|
try Module:init(Args) of |
|
|
|
Result -> |
|
|
|
addNewEpm(Result, EpmHers, Module, Module, EpmSup) |
|
|
|
catch |
|
|
|
throw:Ret -> |
|
|
|
addNewEpm(Ret, EpmHers, Module, Module, EpmSup); |
|
|
|
C:R -> |
|
|
|
{{error, {C, R, ?STACKTRACE()}}, EpmHers, false} |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup) -> |
|
|
|
case doAddEpm(EpmHers, EpmHandler, Args, EpmSup) of |
|
|
|
{ok, _, _} = Result -> |
|
|
|
link(EpmSup), |
|
|
|
Result; |
|
|
|
Ret -> |
|
|
|
Ret |
|
|
|
end. |
|
|
|
|
|
|
|
doSwapEpm(EpmHers, EpmId1, Args1, EpmMId, Args2) -> |
|
|
|
case EpmHers of |
|
|
|
#{EpmId1 := #epmHer{epmSup = EpmSup} = EpmHer} -> |
|
|
|
State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}), |
|
|
|
NewEpmHers = maps:remove(EpmId1, EpmHers), |
|
|
|
case EpmSup of |
|
|
|
false -> |
|
|
|
doAddEpm(NewEpmHers, EpmMId, {Args2, State2}, undefined); |
|
|
|
_ -> |
|
|
|
doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup) |
|
|
|
end; |
|
|
|
undefined -> |
|
|
|
doAddEpm(EpmHers, EpmMId, {Args2, undefined}, undefined) |
|
|
|
end. |
|
|
|
|
|
|
|
doSwapSupEpm(EpmHers, EpmId1, Args1, EpmMId, Args2, EpmSup) -> |
|
|
|
case EpmHers(EpmId1) of |
|
|
|
#{EpmId1 := EpmHer} -> |
|
|
|
State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}), |
|
|
|
NewEpmHers = maps:remove(EpmId1, EpmHers), |
|
|
|
doAddSupEpm(NewEpmHers, EpmMId, {Args2, State2}, EpmSup); |
|
|
|
undefined -> |
|
|
|
doAddSupEpm(EpmHers, EpmMId, {Args2, undefined}, EpmSup) |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
doNotify(EpmHers, Func, Event, _Form) -> |
|
|
|
allNotify(maps:iterator(EpmHers), Func, Event, false, EpmHers, false). |
|
|
|
|
|
|
|
allNotify(Iterator, Func, Event, From, TemEpmHers, IsHib) -> |
|
|
|
case maps:next(Iterator) of |
|
|
|
{K, _V, NextIterator} -> |
|
|
|
{NewEpmHers, NewIsHib} = doEpmHandle(TemEpmHers, K, Func, Event, From), |
|
|
|
allNotify(NextIterator, Func, Event, From, NewEpmHers, IsHib orelse NewIsHib); |
|
|
|
_ -> |
|
|
|
{TemEpmHers, IsHib} |
|
|
|
end. |
|
|
|
|
|
|
|
doEpmHandle(EpmHers, EpmHandler, Func, Event, From) -> |
|
|
|
case EpmHers of |
|
|
|
#{EpmHandler := #epmHer{epmM = EpmM, epmS = EpmS} = EpmHer} -> |
|
|
|
try EpmM:Func(Event, EpmS) of |
|
|
|
Result -> |
|
|
|
handleEpmCR(Result, EpmHers, EpmHer, Event, From) |
|
|
|
catch |
|
|
|
throw:Ret -> |
|
|
|
handleEpmCR(Ret, EpmHers, EpmHer, Event, From); |
|
|
|
C:R -> |
|
|
|
epmTerminate(EpmHer, {error, {C, R, ?STACKTRACE()}}, Event, crash), |
|
|
|
NewEpmHers = maps:remove(EpmHandler, EpmHer), |
|
|
|
{NewEpmHers, false} |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
{EpmHers, false} |
|
|
|
end. |
|
|
|
|
|
|
|
doDeleteEpm(EpmHers, EpmHandler, Args) -> |
|
|
|
case EpmHers of |
|
|
|
#{EpmHandler := EpmHer} -> |
|
|
|
epmTerminate(EpmHer, Args, delete, normal), |
|
|
|
{ok, maps:remove(EpmHandler, EpmHers)}; |
|
|
|
undefined -> |
|
|
|
{{error, module_not_found}, EpmHers} |
|
|
|
end. |
|
|
|
|
|
|
|
%% handleEpmCallbackRet |
|
|
|
handleEpmCR(Result, EpmHers, #epmHer{epmId = EpmId} = EpmHer, Event, From) -> |
|
|
|
case Result of |
|
|
|
ok -> |
|
|
|
{EpmHers, false}; |
|
|
|
{ok, NewEpmS} -> |
|
|
|
MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
{EpmHers#{EpmId := MewEpmHer}, false}; |
|
|
|
{ok, NewEpmS, hibernate} -> |
|
|
|
MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
{EpmHers#{EpmId := MewEpmHer}, true}; |
|
|
|
{swapEpm, NewEpmS, Args1, EpmMId, Args2} -> |
|
|
|
#epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}), |
|
|
|
TemEpmHers = maps:remove(EpmId, EpmHers), |
|
|
|
{_, NewEpmHers, IsHib} = |
|
|
|
case EpmSup of |
|
|
|
undefined -> |
|
|
|
doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined); |
|
|
|
_ -> |
|
|
|
doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup) |
|
|
|
end, |
|
|
|
{NewEpmHers, IsHib}; |
|
|
|
{swapEpm, Reply, NewEpmS, Args1, EpmMId, Args2} -> |
|
|
|
reply(From, Reply), |
|
|
|
#epmHer{epmId = OldEpmMId, epmSup = EpmSup} = MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
State = epmTerminate(MewEpmHer, Args1, swapped, {swapped, OldEpmMId, EpmSup}), |
|
|
|
TemEpmHers = maps:remove(EpmId, EpmHers), |
|
|
|
{_, NewEpmHers, IsHib} = |
|
|
|
case EpmSup of |
|
|
|
undefined -> |
|
|
|
doAddEpm(TemEpmHers, EpmMId, {Args2, State}, undefined); |
|
|
|
_ -> |
|
|
|
doAddSupEpm(TemEpmHers, EpmMId, {Args2, State}, EpmSup) |
|
|
|
end, |
|
|
|
{NewEpmHers, IsHib}; |
|
|
|
removeEpm -> |
|
|
|
epmTerminate(EpmHer, removeEpm, remove, normal), |
|
|
|
{maps:remove(EpmId, EpmHers), false}; |
|
|
|
{removeEpm, Reply} -> |
|
|
|
reply(From, Reply), |
|
|
|
epmTerminate(EpmHer, removeEpm, remove, normal), |
|
|
|
{maps:remove(EpmId, EpmHers), false}; |
|
|
|
{reply, Reply} -> |
|
|
|
reply(From, Reply), |
|
|
|
{EpmHers, false}; |
|
|
|
{reply, Reply, NewEpmS} -> |
|
|
|
reply(From, Reply), |
|
|
|
MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
{EpmHers#{EpmId := MewEpmHer}, false}; |
|
|
|
{reply, Reply, NewEpmS, hibernate} -> |
|
|
|
reply(From, Reply), |
|
|
|
MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS), |
|
|
|
{EpmHers#{EpmId := MewEpmHer}, true}; |
|
|
|
Other -> |
|
|
|
epmTerminate(EpmHer, {error, Other}, Event, crash), |
|
|
|
{maps:remove(EpmId, EpmHers), false} |
|
|
|
end. |
|
|
|
|
|
|
|
epmTerminate(#epmHer{epmM = EpmM, epmS = State} = EpmHer, Args, LastIn, Reason) -> |
|
|
|
case erlang:function_exported(EpmM, terminate, 2) of |
|
|
|
true -> |
|
|
|
Res = (catch EpmM:terminate(Args, State)), |
|
|
|
reportTerminate(EpmHer, Reason, Args, LastIn, Res), |
|
|
|
Res; |
|
|
|
false -> |
|
|
|
reportTerminate(EpmHer, Reason, Args, LastIn, ok), |
|
|
|
ok |
|
|
|
end. |
|
|
|
|
|
|
|
reportTerminate(EpmHer, crash, {error, Why}, LastIn, _) -> |
|
|
|
reportTerminate2(EpmHer, Why, LastIn); |
|
|
|
%% How == normal | shutdown | {swapped, NewHandler, NewSupervisor} |
|
|
|
reportTerminate(EpmHer, How, _, LastIn, _) -> |
|
|
|
reportTerminate2(EpmHer, How, LastIn). |
|
|
|
|
|
|
|
reportTerminate2(#epmHer{epmSup = EpmSup, epmId = EpmId, epmS = State} = EpmHer, Reason, LastIn) -> |
|
|
|
report_error(EpmHer, Reason, State, LastIn), |
|
|
|
case EpmSup of |
|
|
|
undefined -> |
|
|
|
ok; |
|
|
|
_ -> |
|
|
|
EpmSup ! {gen_event_EXIT, EpmId, Reason}, |
|
|
|
ok |
|
|
|
end. |
|
|
|
|
|
|
|
report_error(_EpmHer, normal, _, _) -> ok; |
|
|
|
report_error(_EpmHer, shutdown, _, _) -> ok; |
|
|
|
report_error(_EpmHer, {swapped, _, _}, _, _) -> ok; |
|
|
|
report_error(#epmHer{epmId = EpmId, epmM = EpmM}, Reason, State, LastIn) -> |
|
|
|
?LOG_ERROR( |
|
|
|
#{ |
|
|
|
label => {gen_ipc, epm_terminate}, |
|
|
|
handler => {EpmId, EpmM}, |
|
|
|
name => undefined, |
|
|
|
last_message => LastIn, |
|
|
|
state => State, |
|
|
|
reason => Reason |
|
|
|
}, |
|
|
|
#{ |
|
|
|
domain => [otp], |
|
|
|
report_cb => fun gen_ipc:epm_log/1, |
|
|
|
error_logger => #{tag => error} |
|
|
|
}). |
|
|
|
|
|
|
|
epm_log(#{label := {gen_ipc, epm_terminate}, handler := Handler, name := SName, last_message := LastIn, state := State, reason := Reason}) -> |
|
|
|
Reason1 = |
|
|
|
case Reason of |
|
|
|
{'EXIT', {undef, [{M, F, A, L} | MFAs]}} -> |
|
|
|
case code:is_loaded(M) of |
|
|
|
false -> |
|
|
|
{'module could not be loaded', [{M, F, A, L} | MFAs]}; |
|
|
|
_ -> |
|
|
|
case erlang:function_exported(M, F, length(A)) of |
|
|
|
true -> |
|
|
|
{undef, [{M, F, A, L} | MFAs]}; |
|
|
|
false -> |
|
|
|
{'function not exported', [{M, F, A, L} | MFAs]} |
|
|
|
end |
|
|
|
end; |
|
|
|
{'EXIT', Why} -> |
|
|
|
Why; |
|
|
|
_ -> |
|
|
|
Reason |
|
|
|
end, |
|
|
|
{"** gen_ipc emp handler ~p crashed.~n" |
|
|
|
"** Was installed in ~tp~n" |
|
|
|
"** Last event was: ~tp~n" |
|
|
|
"** When handler state == ~tp~n" |
|
|
|
"** Reason == ~tp~n", [Handler, SName, LastIn, State, Reason1]}; |
|
|
|
epm_log(#{label := {gen_ipc, no_handle_info}, module := Module, message := Msg}) -> |
|
|
|
{"** Undefined handle_info in ~tp~n" |
|
|
|
"** Unhandled message: ~tp~n", [Module, Msg]}. |
|
|
|
|
|
|
|
epmStopAll(EpmHers) -> |
|
|
|
allStop(maps:iterator(EpmHers)). |
|
|
|
|
|
|
|
allStop(Iterator) -> |
|
|
|
case maps:next(Iterator) of |
|
|
|
{_K, V, NextIterator} -> |
|
|
|
epmTerminate(V, stop, 'receive', shutdown), |
|
|
|
case element(#epmHer.epmSup, V) of |
|
|
|
undefined -> |
|
|
|
ignore; |
|
|
|
EpmSup -> |
|
|
|
unlink(EpmSup) |
|
|
|
end, |
|
|
|
allStop(NextIterator); |
|
|
|
none -> |
|
|
|
ok |
|
|
|
end. |
|
|
|
|
|
|
|
epmStopOne(ExitEmpSup, EpmHers) -> |
|
|
|
forStopOne(maps:iterator(EpmHers), ExitEmpSup, EpmHers). |
|
|
|
|
|
|
|
forStopOne(Iterator, ExitEmpSup, TemEpmHers) -> |
|
|
|
case maps:next(Iterator) of |
|
|
|
{K, V, NextIterator} -> |
|
|
|
case element(#epmHer.epmSup, V) =:= ExitEmpSup of |
|
|
|
true -> |
|
|
|
epmTerminate(V, stop, 'receive', shutdown), |
|
|
|
forStopOne(NextIterator, ExitEmpSup, maps:remove(K, TemEpmHers)); |
|
|
|
_ -> |
|
|
|
forStopOne(NextIterator, ExitEmpSup, TemEpmHers) |
|
|
|
end; |
|
|
|
none -> |
|
|
|
TemEpmHers |
|
|
|
end. |
|
|
|
|
|
|
|
epmTerminate(#epmHer{epmM = EpmM, epmS = State} = EpmHer, Args, LastIn, Reason) -> |
|
|
|
case erlang:function_exported(EpmM, terminate, 2) of |
|
|
|
true -> |
|
|
|
Res = (catch EpmM:terminate(Args, State)), |
|
|
|
reportTerminate(EpmHer, Reason, Args, LastIn, Res), |
|
|
|
Res; |
|
|
|
false -> |
|
|
|
reportTerminate(EpmHer, Reason, Args, LastIn, ok), |
|
|
|
ok |
|
|
|
end. |
|
|
|
|
|
|
|
reply({To, Ref}, Msg) -> |
|
|
|
To ! {Ref, Msg}, |
|
|
|
ok. |
|
|
|
|
|
|
|
terminate_server(Reason, Parent, ServerName, EpmHers) -> |
|
|
|
stop_handlers(EpmHers, ServerName), |
|
|
|
do_unlink(Parent, EpmHers), |
|
|
|
exit(Reason). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%% unlink the supervisor process of all supervised handlers. |
|
|
|
%% We do not want a handler supervisor to EXIT due to the |
|
|
|
%% termination of the event manager (server). |
|
|
@ -446,8 +756,8 @@ system_continue(Parent, Debug, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> |
|
|
|
loopEntry(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib). |
|
|
|
|
|
|
|
-spec system_terminate(_, _, _, [_]) -> no_return(). |
|
|
|
system_terminate(Reason, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]) -> |
|
|
|
terminate_server(Reason, Parent, MSL, ServerName). |
|
|
|
system_terminate(Reason, Parent, _Debug, [ServerName, EpmHers, _HibernateAfterTimeout, _Hib]) -> |
|
|
|
terminate_server(Reason, Parent, ServerName, EpmHers). |
|
|
|
|
|
|
|
%%----------------------------------------------------------------- |
|
|
|
%% Module here is sent in the system msg change_code. It specifies |
|
|
|