aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
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/beam
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/beam')
-rw-r--r--erts/emulator/beam/beam_emu.c11
-rw-r--r--erts/emulator/beam/bif.c16
-rw-r--r--erts/emulator/beam/bif.h6
-rw-r--r--erts/emulator/beam/erl_gc.c4
-rw-r--r--erts/emulator/beam/global.h1
5 files changed, 30 insertions, 8 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 16741aa2d7..88ac6cffb1 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1017,8 +1017,6 @@ static BeamInstr* call_error_handler(Process* p, BeamInstr* ip,
static BeamInstr* fixed_apply(Process* p, Eterm* reg, Uint arity) NOINLINE;
static BeamInstr* apply(Process* p, Eterm module, Eterm function,
Eterm args, Eterm* reg) NOINLINE;
-static int hibernate(Process* c_p, Eterm module, Eterm function,
- Eterm args, Eterm* reg) NOINLINE;
static BeamInstr* call_fun(Process* p, int arity,
Eterm* reg, Eterm args) NOINLINE;
static BeamInstr* apply_fun(Process* p, Eterm fun,
@@ -3393,6 +3391,9 @@ void process_main(void)
r(0) = c_p->def_arg_reg[0];
x(1) = c_p->def_arg_reg[1];
x(2) = c_p->def_arg_reg[2];
+ if (c_p->status == P_WAITING) {
+ goto do_schedule;
+ }
Dispatch();
}
reg[0] = r(0);
@@ -5191,7 +5192,7 @@ void process_main(void)
OpCase(i_hibernate): {
SWAPOUT;
- if (hibernate(c_p, r(0), x(1), x(2), reg)) {
+ if (erts_hibernate(c_p, r(0), x(1), x(2), reg)) {
goto do_schedule;
} else {
I = handle_error(c_p, I, reg, hibernate_3);
@@ -6178,8 +6179,8 @@ fixed_apply(Process* p, Eterm* reg, Uint arity)
return ep->address;
}
-static int
-hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg)
+int
+erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Eterm tmp;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index bb237e378a..5cf3f523b8 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1091,10 +1091,20 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
BIF_RETTYPE hibernate_3(BIF_ALIST_3)
{
/*
- * hibernate/3 is implemented as an instruction; therefore
- * this function will never be called.
+ * hibernate/3 is usually translated to an instruction; therefore
+ * this function is only called from HiPE or when the call could not
+ * be translated.
*/
- BIF_ERROR(BIF_P, BADARG);
+ Eterm reg[3];
+
+ if (erts_hibernate(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, reg)) {
+ /*
+ * If hibernate succeeded, TRAP. The process will be suspended
+ * if status is P_WAITING or continue (if any message was in the queue).
+ */
+ BIF_TRAP_CODE_PTR_(BIF_P, BIF_P->i);
+ }
+ return THE_NON_VALUE;
}
/**********************************************************************/
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index a84ee7bb23..615714f7f4 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -201,6 +201,12 @@ do { \
return THE_NON_VALUE; \
} while(0)
+#define BIF_TRAP_CODE_PTR_(p, Code_) do { \
+ *((UWord *) (UWord) ((p)->def_arg_reg + 3)) = (UWord) (Code_); \
+ (p)->freason = TRAP; \
+ return THE_NON_VALUE; \
+ } while(0)
+
extern Export bif_return_trap_export;
#ifdef DEBUG
#define ERTS_BIF_PREP_YIELD_RETURN_X(RET, P, VAL, DEBUG_VAL) \
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 2aa932e7d1..1a405e0c4d 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -33,6 +33,7 @@
#include "erl_gc.h"
#if HIPE
#include "hipe_stack.h"
+#include "hipe_mode_switch.h"
#endif
#define ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT 1
@@ -486,6 +487,9 @@ erts_garbage_collect_hibernate(Process* p)
htop = heap;
n = setup_rootset(p, p->arg_reg, p->arity, &rootset);
+#if HIPE
+ hipe_empty_nstack(p);
+#endif
src = (char *) p->heap;
src_size = (char *) p->htop - src;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index e8a9d5f32f..42aafe6ac6 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1664,6 +1664,7 @@ Uint erts_current_reductions(Process* current, Process *p);
int erts_print_system_version(int to, void *arg, Process *c_p);
+int erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg);
#define seq_trace_output(token, msg, type, receiver, process) \
seq_trace_output_generic((token), (msg), (type), (receiver), (process), NIL)
#define seq_trace_output_exit(token, msg, type, receiver, exitfrom) \