summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Gustavsson <bjorn@erlang.org>2020-06-17 07:14:27 +0200
committerBjörn Gustavsson <bjorn@erlang.org>2020-06-17 07:14:27 +0200
commite79ff7cab1776b1d71b079064f039adb7aa101e7 (patch)
treef36c6217c395ff6f789501856d88a6950c42f869
parent7682a175a35347a2b86f7def4501a3c20657eb96 (diff)
parent3e717efdd526a608d35b943d6863c8dbba53241f (diff)
downloaderlang-e79ff7cab1776b1d71b079064f039adb7aa101e7.tar.gz
Merge branch 'maint'
* maint: Avoid incomplete heaps for crash dumps Robustify binary_SUITE:t2b_system_limit/1
-rw-r--r--erts/emulator/Makefile.in3
-rw-r--r--erts/emulator/beam/dist.c29
-rw-r--r--erts/emulator/beam/erl_bif_info.c28
-rw-r--r--erts/emulator/beam/erl_global_literals.c69
-rw-r--r--erts/emulator/beam/erl_global_literals.h34
-rw-r--r--erts/emulator/beam/erl_process_dump.c7
-rw-r--r--erts/emulator/test/binary_SUITE.erl56
-rw-r--r--lib/observer/test/crashdump_helper.erl23
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl28
9 files changed, 221 insertions, 56 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 6c25a28116..dfaeef9b39 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -950,7 +950,8 @@ RUN_OBJS += \
$(OBJDIR)/erl_msacc.o $(OBJDIR)/erl_lock_flags.o \
$(OBJDIR)/erl_io_queue.o $(OBJDIR)/erl_db_catree.o \
$(ESOCK_RUN_OBJS) $(OBJDIR)/erl_flxctr.o \
- $(OBJDIR)/erl_nfunc_sched.o
+ $(OBJDIR)/erl_nfunc_sched.o \
+ $(OBJDIR)/erl_global_literals.o
LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index de7309b248..eac522e165 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -46,6 +46,7 @@
#include "erl_thr_progress.h"
#include "dtrace-wrapper.h"
#include "erl_proc_sig_queue.h"
+#include "erl_global_literals.h"
#define DIST_CTL_DEFAULT_SIZE 64
@@ -1030,14 +1031,6 @@ trap_function(Eterm func, int arity)
return erts_export_put(am_erlang, func, arity);
}
-/*
- * Sync with dist_util.erl:
- *
- * -record(erts_dflags,
- * {default, mandatory, addable, rejectable, strict_order}).
- */
-static Eterm erts_dflags_record;
-
static BIF_RETTYPE spawn_request_yield_3(BIF_ALIST_3);
void init_dist(void)
@@ -1069,11 +1062,16 @@ void init_dist(void)
am_erts_internal, am_spawn_request_yield,
3, spawn_request_yield_3);
{
- Eterm *hp_start, *hp, **hpp = NULL;
+ Eterm *hp_start, *hp, **hpp = NULL, tuple;
Uint sz = 0, *szp = &sz;
while (1) {
- erts_dflags_record =
- erts_bld_tuple(hpp, szp, 6,
+ /*
+ * Sync with dist_util.erl:
+ *
+ * -record(erts_dflags,
+ * {default, mandatory, addable, rejectable, strict_order}).
+ */
+ tuple = erts_bld_tuple(hpp, szp, 6,
am_erts_dflags,
erts_bld_uint64(hpp, szp, DFLAG_DIST_DEFAULT),
erts_bld_uint64(hpp, szp, DFLAG_DIST_MANDATORY),
@@ -1081,12 +1079,12 @@ void init_dist(void)
erts_bld_uint64(hpp, szp, DFLAG_DIST_REJECTABLE),
erts_bld_uint64(hpp, szp, DFLAG_DIST_STRICT_ORDER));
if (hpp) {
- ASSERT(is_value(erts_dflags_record));
+ ASSERT(is_value(tuple));
ASSERT(hp == hp_start + sz);
- erts_set_literal_tag(&erts_dflags_record, hp_start, sz);
+ erts_register_global_literal(ERTS_LIT_DFLAGS_RECORD, tuple);
break;
}
- hp = hp_start = erts_alloc(ERTS_ALC_T_LITERAL, sz*sizeof(Eterm));
+ hp = hp_start = erts_alloc_global_literal(ERTS_LIT_DFLAGS_RECORD, sz);
hpp = &hp;
szp = NULL;
}
@@ -5032,8 +5030,7 @@ BIF_RETTYPE erts_internal_get_dflags_0(BIF_ALIST_0)
szp = NULL;
}
}
- return erts_dflags_record;
-
+ return erts_get_global_literal(ERTS_LIT_DFLAGS_RECORD);
}
BIF_RETTYPE erts_internal_get_creation_0(BIF_ALIST_0)
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index f20cce7ee4..fde980757b 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -55,6 +55,7 @@
#ifdef HIPE
#include "hipe_arch.h"
#endif
+#include "erl_global_literals.h"
#ifdef ERTS_ENABLE_LOCK_COUNT
#include "erl_lock_count.h"
@@ -151,10 +152,6 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
# define PERFMON_GETPCR _IOR('P', 2, unsigned long long)
#endif
-/* Cached, pre-built {OsType,OsFlavor} and {Major,Minor,Build} tuples */
-static Eterm os_type_tuple;
-static Eterm os_version_tuple;
-
static Eterm
current_function(Process* p, ErtsHeapFactory *hfact, Process* rp,
int full_info, Uint reserve_size, int flags);
@@ -2665,7 +2662,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
NIL));
}
else if (BIF_ARG_1 == am_os_type) {
- BIF_RET(os_type_tuple);
+ BIF_RET(erts_get_global_literal(ERTS_LIT_OS_TYPE));
}
else if (BIF_ARG_1 == am_allocator) {
BIF_RET(erts_allocator_options((void *) BIF_P));
@@ -2685,7 +2682,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
BIF_RET(am_false);
}
else if (BIF_ARG_1 == am_os_version) {
- BIF_RET(os_version_tuple);
+ BIF_RET(erts_get_global_literal(ERTS_LIT_OS_VERSION));
}
else if (BIF_ARG_1 == am_version) {
int n = sys_strlen(ERLANG_VERSION);
@@ -5486,21 +5483,22 @@ static void os_info_init(void)
int major, minor, build;
char* buf = erts_alloc(ERTS_ALC_T_TMP, 1024); /* More than enough */
Eterm* hp;
+ Eterm tuple;
os_flavor(buf, 1024);
flav = erts_atom_put((byte *) buf, sys_strlen(buf), ERTS_ATOM_ENC_LATIN1, 1);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
- hp = erts_alloc(ERTS_ALC_T_LITERAL, (3+4)*sizeof(Eterm));
- os_type_tuple = TUPLE2(hp, type, flav);
- erts_set_literal_tag(&os_type_tuple, hp, 3);
+ hp = erts_alloc_global_literal(ERTS_LIT_OS_TYPE, 3);
+ tuple = TUPLE2(hp, type, flav);
+ erts_register_global_literal(ERTS_LIT_OS_TYPE, tuple);
- hp += 3;
+ hp = erts_alloc_global_literal(ERTS_LIT_OS_VERSION, 4);
os_version(&major, &minor, &build);
- os_version_tuple = TUPLE3(hp,
- make_small(major),
- make_small(minor),
- make_small(build));
- erts_set_literal_tag(&os_version_tuple, hp, 4);
+ tuple = TUPLE3(hp,
+ make_small(major),
+ make_small(minor),
+ make_small(build));
+ erts_register_global_literal(ERTS_LIT_OS_VERSION, tuple);
}
void
diff --git a/erts/emulator/beam/erl_global_literals.c b/erts/emulator/beam/erl_global_literals.c
new file mode 100644
index 0000000000..c3e7b8a70b
--- /dev/null
+++ b/erts/emulator/beam/erl_global_literals.c
@@ -0,0 +1,69 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2020. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "global.h"
+#include "erl_global_literals.h"
+
+struct literal {
+ Eterm term;
+ ErtsLiteralArea* area;
+};
+
+static struct literal literals[ERTS_NUM_GLOBAL_LITERALS];
+
+Eterm* erts_alloc_global_literal(Uint index, Uint sz)
+{
+ ErtsLiteralArea* area;
+ Uint area_sz;
+
+ ASSERT(index < ERTS_NUM_GLOBAL_LITERALS);
+ area_sz = sizeof(ErtsLiteralArea) + (sz-1)*sizeof(Eterm);
+ area = erts_alloc(ERTS_ALC_T_LITERAL, area_sz);
+ area->end = area->start + sz;
+ literals[index].area = area;
+ return area->start;
+}
+
+void erts_register_global_literal(Uint index, Eterm term)
+{
+ Eterm* start;
+
+ ASSERT(index < ERTS_NUM_GLOBAL_LITERALS);
+ start = literals[index].area->start;
+ erts_set_literal_tag(&term, start, literals[index].area->end - start);
+ literals[index].term = term;
+}
+
+Eterm erts_get_global_literal(Uint index)
+{
+ ASSERT(index < ERTS_NUM_GLOBAL_LITERALS);
+ return literals[index].term;
+}
+
+ErtsLiteralArea* erts_get_global_literal_area(Uint index)
+{
+ ASSERT(index < ERTS_NUM_GLOBAL_LITERALS);
+ return literals[index].area;
+}
diff --git a/erts/emulator/beam/erl_global_literals.h b/erts/emulator/beam/erl_global_literals.h
new file mode 100644
index 0000000000..15e873479d
--- /dev/null
+++ b/erts/emulator/beam/erl_global_literals.h
@@ -0,0 +1,34 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2020. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef __ERL_GLOBAL_LITERALS_H__
+#define __ERL_GLOBAL_LITERALS_H__
+
+#define ERTS_LIT_OS_TYPE 0
+#define ERTS_LIT_OS_VERSION 1
+#define ERTS_LIT_DFLAGS_RECORD 2
+
+#define ERTS_NUM_GLOBAL_LITERALS 3
+
+Eterm* erts_alloc_global_literal(Uint index, Uint sz);
+void erts_register_global_literal(Uint index, Eterm term);
+Eterm erts_get_global_literal(Uint index);
+ErtsLiteralArea* erts_get_global_literal_area(Uint index);
+#endif
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a6c1ae14b5..69ff526e14 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -36,6 +36,7 @@
#define ERTS_WANT_EXTERNAL_TAGS
#include "external.h"
#include "erl_proc_sig_queue.h"
+#include "erl_global_literals.h"
#define PTR_FMT "%bpX"
#define ETERM_FMT "%beX"
@@ -840,6 +841,12 @@ dump_literals(fmtfn_t to, void *to_arg)
erts_rlock_old_code(code_ix);
erts_print(to, to_arg, "=literals\n");
+
+ for (i = 0; i < ERTS_NUM_GLOBAL_LITERALS; i++) {
+ ErtsLiteralArea* area = erts_get_global_literal_area(i);
+ dump_module_literals(to, to_arg, area);
+ }
+
for (i = 0; i < num_lit_areas; i++) {
if (lit_areas[i]->off_heap) {
dump_module_literals(to, to_arg, lit_areas[i]);
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 0dc2e84290..49d2dfb983 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -475,10 +475,7 @@ t2b_system_limit(Config) when is_list(Config) ->
memsup:get_system_memory_data()) of
Memory when is_integer(Memory),
Memory > 6*1024*1024*1024 ->
- test_t2b_system_limit(term_to_binary, fun erlang:term_to_binary/1, fun erlang:term_to_binary/2),
- test_t2b_system_limit(term_to_iovec, fun erlang:term_to_iovec/1, fun erlang:term_to_iovec/2),
- garbage_collect(),
- ok;
+ do_t2b_system_limit();
_ ->
{skipped, "Not enough memory on this machine"}
end;
@@ -486,37 +483,52 @@ t2b_system_limit(Config) when is_list(Config) ->
{skipped, "Only interesting on 64-bit builds"}
end.
-test_t2b_system_limit(Name, F1, F2) ->
- io:format("Creating HugeBin~n", []),
- Bits = ((1 bsl 32)+1)*8,
- HugeBin = <<0:Bits>>,
-
+do_t2b_system_limit() ->
+ F = fun() ->
+ io:format("Creating HugeBin~n", []),
+ Bits = (1 bsl 32) + 1,
+ HugeBin = <<0:Bits/unit:8>>,
+ test_t2b_system_limit(HugeBin, term_to_binary,
+ fun erlang:term_to_binary/1,
+ fun erlang:term_to_binary/2),
+ test_t2b_system_limit(HugeBin, term_to_iovec,
+ fun erlang:term_to_iovec/1,
+ fun erlang:term_to_iovec/2),
+ garbage_collect(),
+ ok
+ end,
+ Opts = [{args, "-pa " ++ filename:dirname(code:which(?MODULE))}],
+ {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, Opts),
+ erpc:call(Node, F).
+
+test_t2b_system_limit(HugeBin, Name, F1, F2) ->
io:format("Testing ~p(HugeBin)~n", [Name]),
- {'EXIT',{system_limit,[{erlang,Name,
- [HugeBin],
- _} |_]}} = (catch F1(HugeBin)),
+ {'EXIT',{system_limit,[{erlang,Name,[HugeBin],_}|_]}} =
+ t2b_eval(fun() -> F1(HugeBin) end),
io:format("Testing ~p(HugeBin, [compressed])~n", [Name]),
- {'EXIT',{system_limit,[{erlang,Name,
- [HugeBin, [compressed]],
- _} |_]}} = (catch F2(HugeBin, [compressed])),
+ {'EXIT',{system_limit,[{erlang,Name,[HugeBin,[compressed]],_}|_]}} =
+ t2b_eval(fun() -> F2(HugeBin, [compressed]) end),
%% Check that it works also after we have trapped...
io:format("Creating HugeListBin~n", []),
- HugeListBin = [lists:duplicate(2000000,2000000), HugeBin],
+ HugeListBin = [lists:duplicate(2000000, 2000000), HugeBin],
io:format("Testing ~p(HugeListBin)~n", [Name]),
- {'EXIT',{system_limit,[{erlang,Name,
- [HugeListBin],
- _} |_]}} = (catch F1(HugeListBin)),
+ {'EXIT',{system_limit,[{erlang,Name,[HugeListBin],_}|_]}} =
+ t2b_eval(fun() -> F1(HugeListBin) end),
io:format("Testing ~p(HugeListBin, [compressed])~n", [Name]),
- {'EXIT',{system_limit,[{erlang,Name,
- [HugeListBin, [compressed]],
- _} |_]}} = (catch F2(HugeListBin, [compressed])),
+ {'EXIT',{system_limit,[{erlang,Name,[HugeListBin,[compressed]],_}|_]}} =
+ t2b_eval(fun() -> F2(HugeListBin, [compressed]) end),
ok.
+t2b_eval(F) ->
+ Result = (catch F()),
+ io:put_chars(io_lib:format("~P\n", [Result,100])),
+ Result.
+
term_to_iovec(Config) when is_list(Config) ->
Bin = list_to_binary(lists:duplicate(1000,100)),
Bin2 = list_to_binary(lists:duplicate(65,100)),
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index 5c77330e49..0f0947065a 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -23,7 +23,8 @@
dump_maps/0,create_maps/0,
create_binaries/0,create_sub_binaries/1,
dump_persistent_terms/0,
- create_persistent_terms/0]).
+ create_persistent_terms/0,
+ dump_global_literals/0]).
-compile(r20).
-include_lib("common_test/include/ct.hrl").
@@ -207,3 +208,23 @@ create_persistent_terms() ->
persistent_term:put({?MODULE,first}, {pid,42.0}),
persistent_term:put({?MODULE,second}, [1,2,3]),
{persistent_term:get({?MODULE,first}),persistent_term:get({?MODULE,second})}.
+
+%%%
+%%% Test dumping of global literals such as the tuple returned from os:type/0
+%%% (from OTP 23.1).
+%%%
+
+dump_global_literals() ->
+ Parent = self(),
+ F = fun() ->
+ register(aaaaaaaa_global_literals, self()),
+ put(global_literals, {os:type(),os:version()}),
+ Parent ! {self(),done},
+ receive _ -> ok end
+ end,
+ Pid = spawn_link(F),
+ receive
+ {Pid,done} ->
+ unlink(Pid),
+ {ok,Pid}
+ end.
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 31cf7011d4..4e0fd68f50 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -619,6 +619,21 @@ special(File,Procs) ->
Pts = proplists:get_value(pts,Dict),
io:format(" persistent terms ok",[]),
ok;
+ ".global_literals" ->
+ %% I registered a process as aaaaaaaa_global_literals in
+ %% the dump to make sure it will be the first in the list
+ %% when sorted on names.
+ [#proc{pid=Pid0,name=Name}|_Rest] = lists:keysort(#proc.name,Procs),
+ "aaaaaaaa_global_literals" = Name,
+ Pid = pid_to_list(Pid0),
+ {ok,ProcDetails=#proc{},[]} = crashdump_viewer:proc_details(Pid),
+ io:format(" process details ok",[]),
+
+ #proc{dict=Dict} = ProcDetails,
+ Globals = proplists:get_value(global_literals,Dict),
+ Globals = {os:type(),os:version()},
+ io:format(" global_literals ok",[]),
+ ok;
_ ->
ok
end,
@@ -704,9 +719,10 @@ do_create_dumps(DataDir,Rel) ->
CD6 = dump_with_unicode_atoms(DataDir,Rel,"unicode"),
CD7 = dump_with_maps(DataDir,Rel,"maps"),
CD8 = dump_with_persistent_terms(DataDir,Rel,"persistent_terms"),
+ CD9 = dump_with_global_literals(DataDir,Rel,"global_literals"),
TruncDumpMod = truncate_dump_mod(CD1),
TruncatedDumpsBinary = truncate_dump_binary(CD1),
- {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,
+ {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,CD9,
TruncDumpMod|TruncatedDumpsBinary],
DosDump};
_ ->
@@ -886,6 +902,16 @@ dump_with_persistent_terms(DataDir,Rel,DumpName) ->
?t:stop_node(n1),
CD.
+dump_with_global_literals(DataDir,Rel,DumpName) ->
+ Opt = rel_opt(Rel),
+ Pz = "-pz \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
+ PzOpt = [{args,Pz}],
+ {ok,N1} = ?t:start_node(n1,peer,Opt ++ PzOpt),
+ {ok,_Pid} = rpc:call(N1,crashdump_helper,dump_global_literals,[]),
+ CD = dump(N1,DataDir,Rel,DumpName),
+ ?t:stop_node(n1),
+ CD.
+
dump(Node,DataDir,Rel,DumpName) ->
Crashdump = filename:join(DataDir, dump_prefix(Rel)++DumpName),
rpc:call(Node,os,putenv,["ERL_CRASH_DUMP",Crashdump]),