From c054ac3d4df7fe8b2f58204e677f275bd8f0e60c Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 30 Oct 2013 16:46:54 +0100 Subject: wx: Fix cleanup of event handlers Event handlers was not removed after objects/process had been delete/died, which causes memory leakage and that fun's was kept in the wx_server process. Code that might be purged and the server died. --- lib/wx/test/wx_event_SUITE.erl | 77 +++++++++++++++++++++++++++++++++++++++++- lib/wx/test/wx_test_lib.erl | 20 ++++++----- 2 files changed, 87 insertions(+), 10 deletions(-) (limited to 'lib/wx/test') diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl index f19adb430d..6a9f19ad51 100644 --- a/lib/wx/test/wx_event_SUITE.erl +++ b/lib/wx/test/wx_event_SUITE.erl @@ -48,7 +48,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [connect, disconnect, connect_msg_20, connect_cb_20, mouse_on_grid, spin_event, connect_in_callback, recursive, - char_events + char_events, callback_clean ]. groups() -> @@ -420,3 +420,78 @@ char_events(Config) -> wx_test_lib:flush(), wx_test_lib:wx_destroy(Frame, Config). + +callback_clean(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +callback_clean(Config) -> + %% Be sure that event handling are cleanup up correctly and don't keep references to old + %% fun's and event listeners + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame Window"), + wxFrame:show(Frame), + + %% wx:debug([verbose,driver]), + Dlg = wxDialog:new(Frame, ?wxID_ANY, "Testing"), + Panel = wxPanel:new(Dlg, []), + Sizer = wxBoxSizer:new(?wxVERTICAL), + Button = wxButton:new(Panel, 600, [{label, "Foobar"}]), + wxSizer:add(Sizer, Button, [{proportion,1}, {flag, ?wxEXPAND}]), + wxSizer:add(Sizer, wxDialog:createStdDialogButtonSizer(Dlg,?wxOK bor ?wxCANCEL)), + wxDialog:setSizerAndFit(Dlg, Sizer), + + Env = wx:get_env(), + SetupEventHandlers = + fun() -> + wx:set_env(Env), + Me = self(), + Print = fun(#wx{id=ID, event=#wxCommand{}},Ev) -> + io:format("~p Clicked ~p~n", [self(), ID]), + Me ! #wx{event=#wxClose{}}, + wxEvent:skip(Ev, [{skip, true}]); + (#wx{id=ID, event=#wxClose{}},Ev) -> + io:format("~p Closed ~p~n", [self(), ID]), + wxEvent:skip(Ev, [{skip, true}]) + end, + + wxDialog:connect(Dlg, command_button_clicked,[{callback,Print}]), + wxDialog:connect(Dlg, close_window, [{skip, true}]) + end, + ?m({[],[],[]}, white_box_check_event_handlers()), + Pid = spawn_link(fun() -> + SetupEventHandlers(), + receive #wx{event=#wxClose{}} -> ok; + remove -> ok + end + end), + timer:sleep(500), %% Give it time to remove it + ?m({[{Pid,_,_}],[_],[_]}, white_box_check_event_handlers()), + + Pid ! remove, + timer:sleep(500), %% Give it time to remove it + ?m({[],[],[]}, white_box_check_event_handlers()), + + SetupEventHandlers(), + ?m({[{_,_,_}],[_],[_]}, white_box_check_event_handlers()), + + wxDialog:show(Dlg), + wx_test_lib:wx_close(Dlg, Config), + wxDialog:destroy(Dlg), + timer:sleep(500), %% Give it time to remove it + ?m({[],[],[]}, white_box_check_event_handlers()), + + wx_test_lib:flush(), + io:format("**Deleting Frame**~n",[]), + wx_test_lib:wx_destroy(Frame, Config). + %% timer:sleep(infinity), + %% ok. + +white_box_check_event_handlers() -> + {_,_,Server,_} = wx:get_env(), + {status, _, _, [Env, _, _, _, Data]} = sys:get_status(Server), + [_H, _data, {data, [{_, Record}]}] = Data, + {state, _Port1, _Port2, Users, [], CBs, _Next} = Record, + {[{Pid, Evs, Listener} || + {Pid, {user, Evs, Listener}} <- gb_trees:to_list(Users), + (Evs =/= [] orelse Listener =/= undefined)], %% Ignore empty + gb_trees:to_list(CBs), + [Funs || Funs = {Id, {Fun,_}} <- Env, is_integer(Id), is_function(Fun)] + }. diff --git a/lib/wx/test/wx_test_lib.erl b/lib/wx/test/wx_test_lib.erl index 8509d6be6f..9b65a50864 100644 --- a/lib/wx/test/wx_test_lib.erl +++ b/lib/wx/test/wx_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -129,28 +129,30 @@ pick_msg() -> user_available(Config) -> false /= proplists:get_value(user, Config, false). - wx_destroy(Frame, Config) -> + wx_close(Frame, Config), + ?m(ok, wx:destroy()). + +wx_close(Frame, Config) -> case proplists:get_value(user, Config, false) of false -> timer:sleep(100), - ?m(ok, wxFrame:destroy(Frame)), - ?m(ok, wx:destroy()); + ?m(ok, wxWindow:destroy(Frame)); true -> timer:sleep(500), - ?m(ok, wxFrame:destroy(Frame)), - ?m(ok, wx:destroy()); + ?m(ok, wxWindow:destroy(Frame)); step -> %% Wait for user to close window ?m(ok, wxEvtHandler:connect(Frame, close_window, [{skip,true}])), - wait_for_close() + wait_for_close(), + catch wxEvtHandler:disconnect(Frame, close_window), + ok end. wait_for_close() -> receive #wx{event=#wxClose{}} -> - ?log("Got close~n",[]), - ?m(ok, wx:destroy()); + ?log("Got close~n",[]); #wx{obj=Obj, event=Event} -> try Name = wxTopLevelWindow:getTitle(Obj), -- cgit v1.2.3 From 76b4def27cf893cf25a7e72e7871180bd4bfd003 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 6 Nov 2013 14:00:16 +0100 Subject: wx: Fix crash in wxe_server cleanup Do not use disconnect event listener when we are exiting the port, it may interfere with window destructions and cause a crash. --- lib/wx/test/wx_xtra_SUITE.erl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lib/wx/test') diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl index a2d4c26319..8d5d7ddb6a 100644 --- a/lib/wx/test/wx_xtra_SUITE.erl +++ b/lib/wx/test/wx_xtra_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2012. All Rights Reserved. +%% Copyright Ericsson AB 2009-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -129,15 +129,19 @@ app_dies(_Config) -> app_dies2(Test, N) -> spawn_link(fun() -> Test(N) end), - receive - {'EXIT', _, {oops, last}} -> ok; - {'EXIT', _, {oops, _}} -> app_dies2(Test, N+1) + receive + {'EXIT', _, {oops, Server, What}} -> + Ref = erlang:monitor(process, Server), + receive {'DOWN', Ref, _, _, _} -> ok end, + timer:sleep(100), + What =/= last andalso app_dies2(Test, N+1) end. oops(Die, Line) when (Die =:= last) orelse (Die =< Line) -> - timer:sleep(300), + timer:sleep(200), ?log(" Exits at line ~p~n",[Line]), - exit({oops, Die}); + Server = element(3, wx:get_env()), + exit({oops, Server, Die}); oops(_,_) -> ok. -- cgit v1.2.3