aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
authorPaul Guyot <[email protected]>2010-09-27 18:10:24 +0200
committerPaul Guyot <[email protected]>2011-01-29 09:36:14 +0100
commitce00ecb42c136b55d91ece38c9cf29b0d0cc6380 (patch)
treee7db4a8ca6ffc1e4238a65557e904f420efcc411 /erts/emulator/test
parent62dad961329a603110ce0e1d3f62554cc5228152 (diff)
downloadotp-ce00ecb42c136b55d91ece38c9cf29b0d0cc6380.tar.gz
otp-ce00ecb42c136b55d91ece38c9cf29b0d0cc6380.tar.bz2
otp-ce00ecb42c136b55d91ece38c9cf29b0d0cc6380.zip
Fix several bugs related to hibernate/3 and HiPE
This commit fixes four related bugs: - calling hibernate/3 using a dynamic call would fail with badarg as hibernate/3 as a BIF was not implemented. hibernate/3 is generally provided as a Beam instruction, and code is translated to use this instruction when loaded. - calling hibernate/3 from HiPE would fail with badarg because this would call the aforementioned BIF which was not implemented. - calling hibernate/3 with some HiPE-native garbage in the process heap would randomly crash at the next garbage collect. This bug only happened in a complex, yet reproduceable scenarios, where native code calls beam code that calls hibernate/3, and the process has some garbage when being hibernated and the process generates garbage when awaken. - when entering HiPE, the process current_function can be set and be inaccurate. The fix is three folded: - hibernate_3 BIF now actually works instead of throwing a badarg. While hibernate_3 BIF was (usually) not called from BEAM, it is called from HiPE. hibernate behaviour is very close to the scheduler and this is why it is implemented as an instruction in BEAM. The fix consists in doing the actual hibernation (through the now exported erts_hibernate function) and setting the process flag to TRAP as well as the process status to P_WAITING. On BIF epilogue in both BEAM and HiPE, this status is tested on TRAP and if set, the scheduler is invoked. The i_hibernate instruction and translation code is now redundant and could be deleted. - hibernation now also empties the HiPE native stack, with a new function hipe_empty_nstack provided by Mikael Pettersson. - when entering HiPE through hipe_mode_switch, p->current is cleared, as suggested by Mikael Pettersson. p->current normally hold a pointer to the {M,F,A} of the current function if it exists. When hibernating, it is set to {erlang,hibernate,3}, and all stdlib hibernate tests (gen_server_SUITE:hibernate/1, proc_lib_suite:hibernate/1, etc.) actually rely on this information. Clearing p->current fixes the tests and avoids the surprise one might have when querying the process info of a process that hibernated and woke up in a native function. Non-regression tests are provided, a test for the dynamic call as well as a Makefile-handled duplication of the hibernate_SUITE into hibernate_native_SUITE for the HiPE case.
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/Makefile12
-rw-r--r--erts/emulator/test/hibernate_SUITE.erl43
2 files changed, 51 insertions, 4 deletions
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 7259e1b84d..4b142503a0 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -122,10 +122,14 @@ NO_OPT= bs_bincomp \
bs_utf \
guard
+NATIVE= hibernate
NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE)
NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl)
+NATIVE_MODULES= $(NATIVE:%=%_native_SUITE)
+NATIVE_ERL_FILES= $(NATIVE_MODULES:%=%.erl)
+
ERL_FILES= $(MODULES:%=%.erl)
TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
@@ -151,7 +155,7 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include
# Targets
# ----------------------------------------------------
-make_emakefile: $(NO_OPT_ERL_FILES)
+make_emakefile: $(NO_OPT_ERL_FILES) $(NATIVE_ERL_FILES)
# This special rule can be removed when communication with R7B nodes
# is no longer supported.
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \
@@ -160,6 +164,8 @@ make_emakefile: $(NO_OPT_ERL_FILES)
$(MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +native $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(NATIVE_MODULES) >> $(EMAKEFILE)
tests debug opt: make_emakefile
erl $(ERL_MAKE_FLAGS) -make
@@ -178,6 +184,9 @@ docs:
%_no_opt_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_native_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -190,6 +199,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) $(EMAKEFILE) $(TEST_SPEC_FILES) \
$(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(RELSYSDIR)
+ $(INSTALL_DATA) $(NATIVE_ERL_FILES) $(RELSYSDIR)
chmod -f -R u+w $(RELSYSDIR)
tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
diff --git a/erts/emulator/test/hibernate_SUITE.erl b/erts/emulator/test/hibernate_SUITE.erl
index 4d36076d12..f3f9ba7724 100644
--- a/erts/emulator/test/hibernate_SUITE.erl
+++ b/erts/emulator/test/hibernate_SUITE.erl
@@ -22,14 +22,14 @@
-include("test_server.hrl").
-export([all/1,init_per_testcase/2,fin_per_testcase/2,
- basic/1,min_heap_size/1,bad_args/1,
+ basic/1,dynamic_call/1,min_heap_size/1,bad_args/1,
messages_in_queue/1,undefined_mfa/1, no_heap/1]).
%% Used by test cases.
--export([basic_hibernator/1,messages_in_queue_restart/2, no_heap_loop/0]).
+-export([basic_hibernator/1,dynamic_call_hibernator/2,messages_in_queue_restart/2, no_heap_loop/0]).
all(suite) ->
- [basic,min_heap_size,bad_args,messages_in_queue,undefined_mfa,no_heap].
+ [basic,dynamic_call,min_heap_size,bad_args,messages_in_queue,undefined_mfa,no_heap].
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
Dog = ?t:timetrap(?t:minutes(3)),
@@ -138,10 +138,47 @@ whats_up_calc(A1, A2, A3, A4, A5, A6, A7, A8, A9, Acc) ->
whats_up_calc(A1-1, A2+1, A3+2, A4+3, A5+4, A6+5, A7+6, A8+7, A9+8, [A1,A2|Acc]).
%%%
+%%% Testing a call to erlang:hibernate/3 that the compiler and loader do not
+%%% translate to an instruction.
+%%%
+
+dynamic_call(Config) when is_list(Config) ->
+ Ref = make_ref(),
+ Info = {self(),Ref},
+ ExpectedHeapSz = case erlang:system_info(heap_type) of
+ private -> erts_debug:size([Info]);
+ hybrid -> erts_debug:size([a|b])
+ end,
+ ?line Child = spawn_link(fun() -> ?MODULE:dynamic_call_hibernator(Info, hibernate) end),
+ ?line hibernate_wake_up(100, ExpectedHeapSz, Child),
+ ?line Child ! please_quit_now,
+ ok.
+
+dynamic_call_hibernator(Info, Function) ->
+ {catchlevel,0} = process_info(self(), catchlevel),
+ receive
+ Any ->
+ dynamic_call_hibernator_msg(Any, Function, Info),
+ dynamic_call_hibernator(Info, Function)
+ end.
+
+dynamic_call_hibernator_msg({hibernate,_}, Function, Info) ->
+ catch apply(erlang, Function, [?MODULE, basic_hibernator, [Info]]),
+ exit(hibernate_returned);
+dynamic_call_hibernator_msg(Msg, _Function, Info) ->
+ basic_hibernator_msg(Msg, Info).
+
+%%%
%%% Testing setting the minimum heap size.
%%%
min_heap_size(Config) when is_list(Config) ->
+ case test_server:is_native(?MODULE) of
+ true -> {skip, "Test case relies on trace which is not available in HiPE"};
+ false -> min_heap_size_1(Config)
+ end.
+
+min_heap_size_1(Config) when is_list(Config) ->
?line erlang:trace(new, true, [call]),
MFA = {?MODULE,min_hibernator,1},
?line 1 = erlang:trace_pattern(MFA, true, [local]),