diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index 6447da17156c..09921b4e0333 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -258,6 +258,7 @@ using exit signals. -record(server_data, {parent :: pid(), tag = make_ref() :: reference(), name :: term(), + server_name :: term(), module :: module(), hibernate_after :: timeout(), handle_call :: fun((Request :: term(), From :: from(), State :: term()) -> @@ -2206,7 +2207,7 @@ according to `ServerName`. enter_loop(Mod, Options, State, ServerName, Action) when is_atom(Mod), is_list(Options) -> Name = gen:get_proc_name(ServerName), - ServerData = server_data(gen:get_parent(), Name, Mod, gen:hibernate_after(Options)), + ServerData = server_data(gen:get_parent(), ServerName, Name, Mod, gen:hibernate_after(Options)), case handle_action(ServerData, Action) of error -> gen:unregister_name(Name), @@ -2231,7 +2232,7 @@ init_it(Starter, self, Name, Mod, Args, Options) -> init_it(Starter, self(), Name, Mod, Args, Options); init_it(Starter, Parent, Name0, Mod, Args, Options) -> Name = gen:name(Name0), - ServerData = server_data(Parent, Name, Mod, gen:hibernate_after(Options)), + ServerData = server_data(Parent, Name0, Name, Mod, gen:hibernate_after(Options)), Debug = gen:debug_options(Name, Options), case init_it(Mod, Args) of {ok, {ok, State}} -> @@ -2350,12 +2351,13 @@ cancel_timer([]) -> cancel_timer([TRef | _]) -> ok = erlang:cancel_timer(TRef, [{async, true}, {info, false}]). --compile({inline, [server_data/4, update_callback_cache/1]}). +-compile({inline, [server_data/5, update_callback_cache/1]}). -server_data(Parent, Name, Mod, HibernateAfter) -> +server_data(Parent, ServerName, Name, Mod, HibernateAfter) -> #server_data{ parent = Parent, name = Name, + server_name = ServerName, module = Mod, hibernate_after = HibernateAfter, handle_call = fun Mod:handle_call/3, @@ -2731,6 +2733,7 @@ terminate(ServerData, State, Msg, From, Class, Reason, Stacktrace, Debug) -> -spec terminate(_, _, _, _, _, _, _, _, _) -> no_return(). terminate(ServerData, State, Msg, From, Class, Reason, Stacktrace, Debug, ReportStacktrace) -> Reply = try_terminate(ServerData, State, catch_result(Class, Reason, Stacktrace)), + gen:unregister_name(ServerData#server_data.server_name), case Reply of {'EXIT', C, R, S} -> error_info(ServerData, State, Msg, From, R, S, Debug), diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 325801e2433a..604a1eaedd62 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -57,7 +57,8 @@ undef_handle_continue/1, format_log_1/1, format_log_2/1, format_log_with_process_label/1, - reply_by_alias_with_payload/1 + reply_by_alias_with_payload/1, + terminate_unregisters/1 ]). -export([stop1/1, stop2/1, stop3/1, stop4/1, stop5/1, stop6/1, stop7/1, @@ -113,7 +114,8 @@ all() -> call_with_huge_message_queue, {group, undef_callbacks}, undef_in_terminate, undef_in_handle_info, format_log_1, format_log_2, format_log_with_process_label, - reply_by_alias_with_payload]. + reply_by_alias_with_payload, + terminate_unregisters]. groups() -> [{stop, [], @@ -3114,6 +3116,41 @@ reply_by_alias_with_payload(Config) when is_list(Config) -> ok end. +terminate_unregisters(_Config) -> + dummy_via:reset(), + + Name = {via, dummy_via, ?FUNCTION_NAME}, + Test = self(), + Parent = spawn(fun() -> + {ok, Pid} = start_link(spec_init_via, [{ok, Name}, []]), + Test ! {server, Pid}, + timer:sleep(infinity) + end), + Server = receive {server, Pid} -> Pid end, + + Session = trace:session_create(?MODULE, self(), []), + _ = trace:function(Session, {dummy_via, unregister_name, 1}, true, []), + _ = trace:process(Session, all, true, [call]), + + Ref = monitor(process, Server), + exit(Parent, shutdown), + + % ensure unregister was called + receive + {trace, Server, call, {dummy_via, unregister_name, [Name]}} -> ok + after 500 -> + ct:fail("unregister not called") + end, + receive + {'DOWN', Ref, process, Server, _} -> ok + after + 500 -> + ct:fail("server didn't terminate") + end, + trace:session_destroy(Session), + ok. + + %%-------------------------------------------------------------- %% Help functions to spec_init_* start_link(Init, Options) ->