diff options
83 files changed, 468 insertions, 306 deletions
diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot Binary files differindex 1f7f088a77..26cd9e4d5e 100644 --- a/bootstrap/bin/no_dot_erlang.boot +++ b/bootstrap/bin/no_dot_erlang.boot diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex 1f7f088a77..26cd9e4d5e 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex 1f7f088a77..26cd9e4d5e 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex 07acbb1da7..78b75359a6 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa.beam b/bootstrap/lib/compiler/ebin/beam_ssa.beam Binary files differindex 9ba124a92d..0327230a58 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam Binary files differindex 50412bc8de..b9bb997cc7 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam Binary files differindex e59340de4f..cb06630012 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam Binary files differindex f6bd1b7a69..782073698e 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam Binary files differindex c9838883ef..b8588725b4 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam Binary files differindex 3de363dbb6..e22cb5c846 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_share.beam b/bootstrap/lib/compiler/ebin/beam_ssa_share.beam Binary files differindex ea8e83d919..d975cebf48 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_share.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_share.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam Binary files differindex c13b25bac3..0403230604 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex 9d0c34a94a..050789f481 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex 57cfc6b932..ebe42547ee 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index c0483e7801..e086da1b68 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -19,7 +19,7 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "7.3.2"}, + {vsn, "7.4.4"}, {modules, [ beam_a, beam_asm, diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam Binary files differindex 2423c9b2ea..a2b3167e10 100644 --- a/bootstrap/lib/compiler/ebin/core_pp.beam +++ b/bootstrap/lib/compiler/ebin/core_pp.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_alias.beam b/bootstrap/lib/compiler/ebin/sys_core_alias.beam Binary files differindex 622221a8b0..b769b6be41 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_alias.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_alias.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex 243b911ac6..3cbbdfd88b 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam Binary files differindex 41e4bd4ab2..204b15fcf2 100644 --- a/bootstrap/lib/kernel/ebin/code.beam +++ b/bootstrap/lib/kernel/ebin/code.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam Binary files differindex 17f65d6ceb..0a781001dc 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_1.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam Binary files differindex f6022dca19..0d6541ee53 100644 --- a/bootstrap/lib/kernel/ebin/gen_udp.beam +++ b/bootstrap/lib/kernel/ebin/gen_udp.beam diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam Binary files differindex 396f1166f1..dcec55421c 100644 --- a/bootstrap/lib/kernel/ebin/group.beam +++ b/bootstrap/lib/kernel/ebin/group.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 7ff507242b..de7d9c2e57 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam Binary files differindex b0c67afe90..f64311e166 100644 --- a/bootstrap/lib/kernel/ebin/inet.beam +++ b/bootstrap/lib/kernel/ebin/inet.beam diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam Binary files differindex c12c6f4afc..ac4be100e8 100644 --- a/bootstrap/lib/kernel/ebin/inet6_udp.beam +++ b/bootstrap/lib/kernel/ebin/inet6_udp.beam diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam Binary files differindex 20d795e75f..a835fa1a74 100644 --- a/bootstrap/lib/kernel/ebin/inet_db.beam +++ b/bootstrap/lib/kernel/ebin/inet_db.beam diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam Binary files differindex afc4999c42..8166eca5de 100644 --- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam +++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam Binary files differindex 84c0169d4b..e8935134b5 100644 --- a/bootstrap/lib/kernel/ebin/inet_parse.beam +++ b/bootstrap/lib/kernel/ebin/inet_parse.beam diff --git a/bootstrap/lib/kernel/ebin/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam Binary files differindex 62156a3284..5853bde54f 100644 --- a/bootstrap/lib/kernel/ebin/inet_udp.beam +++ b/bootstrap/lib/kernel/ebin/inet_udp.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index 5ec7c41dbe..cb13db1a89 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -22,7 +22,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "6.3.1"}, + {vsn, "6.4.1"}, {modules, [application, application_controller, application_master, @@ -74,6 +74,7 @@ logger_simple_h, logger_std_h, logger_sup, + net, net_adm, net_kernel, os, diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam Binary files differindex 11be83a49e..2832938d95 100644 --- a/bootstrap/lib/kernel/ebin/kernel.beam +++ b/bootstrap/lib/kernel/ebin/kernel.beam diff --git a/bootstrap/lib/kernel/ebin/local_udp.beam b/bootstrap/lib/kernel/ebin/local_udp.beam Binary files differindex cc5f46f746..33ed76e5cd 100644 --- a/bootstrap/lib/kernel/ebin/local_udp.beam +++ b/bootstrap/lib/kernel/ebin/local_udp.beam diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam Binary files differindex b0f56d9a62..c8eb73a076 100644 --- a/bootstrap/lib/kernel/ebin/logger_std_h.beam +++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam diff --git a/bootstrap/lib/kernel/ebin/net.beam b/bootstrap/lib/kernel/ebin/net.beam Binary files differnew file mode 100644 index 0000000000..44b1f10603 --- /dev/null +++ b/bootstrap/lib/kernel/ebin/net.beam diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam Binary files differindex f3573d95af..8214d9d6aa 100644 --- a/bootstrap/lib/kernel/ebin/user.beam +++ b/bootstrap/lib/kernel/ebin/user.beam diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam Binary files differindex 1b59423b71..43df5afa36 100644 --- a/bootstrap/lib/kernel/ebin/user_drv.beam +++ b/bootstrap/lib/kernel/ebin/user_drv.beam diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam Binary files differindex c61132b2de..17e061b1d0 100644 --- a/bootstrap/lib/stdlib/ebin/c.beam +++ b/bootstrap/lib/stdlib/ebin/c.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam Binary files differindex 046de3bd5a..f73509ae3f 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v9.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam diff --git a/bootstrap/lib/stdlib/ebin/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam Binary files differindex 772332cd08..fabe782d90 100644 --- a/bootstrap/lib/stdlib/ebin/digraph_utils.beam +++ b/bootstrap/lib/stdlib/ebin/digraph_utils.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam Binary files differindex 90b3858207..5ef1521371 100644 --- a/bootstrap/lib/stdlib/ebin/erl_eval.beam +++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 62838ed771..c73ecdf942 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam Binary files differindex 3b30d3e8c7..18538620b7 100644 --- a/bootstrap/lib/stdlib/ebin/erl_scan.beam +++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam Binary files differindex 3c5004871d..871ccd82d4 100644 --- a/bootstrap/lib/stdlib/ebin/erl_tar.beam +++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam Binary files differindex b1cf286cea..350316dfcc 100644 --- a/bootstrap/lib/stdlib/ebin/ets.beam +++ b/bootstrap/lib/stdlib/ebin/ets.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam Binary files differindex 57c700cb31..b0f4177d71 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam diff --git a/bootstrap/lib/stdlib/ebin/ordsets.beam b/bootstrap/lib/stdlib/ebin/ordsets.beam Binary files differindex 9e49566404..44f9e5d8b5 100644 --- a/bootstrap/lib/stdlib/ebin/ordsets.beam +++ b/bootstrap/lib/stdlib/ebin/ordsets.beam diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam Binary files differindex f4d803b1ee..7f1e6140bf 100644 --- a/bootstrap/lib/stdlib/ebin/rand.beam +++ b/bootstrap/lib/stdlib/ebin/rand.beam diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam Binary files differindex 5662594d4c..e16327b906 100644 --- a/bootstrap/lib/stdlib/ebin/re.beam +++ b/bootstrap/lib/stdlib/ebin/re.beam diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam Binary files differindex f64faafa52..3a90a07add 100644 --- a/bootstrap/lib/stdlib/ebin/sofs.beam +++ b/bootstrap/lib/stdlib/ebin/sofs.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index ffb56f8306..41c1f14bbc 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -20,7 +20,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "3.8.1"}, + {vsn, "3.9.2"}, {modules, [array, base64, beam_lib, @@ -108,7 +108,7 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-@OTP-15128@","crypto-3.3", + {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-@OTP-15831:OTP-15836:OTP-15889@","crypto-3.3", "compiler-5.0"]} ]}. diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam Binary files differindex 5d1d66892b..ee19fb41a4 100644 --- a/bootstrap/lib/stdlib/ebin/string.beam +++ b/bootstrap/lib/stdlib/ebin/string.beam diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam Binary files differindex a46ade8602..a3f46b5983 100644 --- a/bootstrap/lib/stdlib/ebin/sys.beam +++ b/bootstrap/lib/stdlib/ebin/sys.beam diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam Binary files differindex b57c84a302..7255fdca63 100644 --- a/bootstrap/lib/stdlib/ebin/uri_string.beam +++ b/bootstrap/lib/stdlib/ebin/uri_string.beam diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam Binary files differindex cd6274efe5..75c2289f47 100644 --- a/bootstrap/lib/stdlib/ebin/zip.beam +++ b/bootstrap/lib/stdlib/ebin/zip.beam diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 0e82ceba7d..2183f75487 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -2553,6 +2553,7 @@ os_prompt%</pre> true > is_map_key(value,Map). false</code> + <p>Allowed in guard tests.</p> </desc> </func> diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 2e33a8a782..67c486a0db 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -533,13 +533,34 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { case EXPORT_DEF: { Export* ep = *((Export **) (export_val(wobj) + 1)); - Atom* module = atom_tab(atom_val(ep->info.mfa.module)); - Atom* name = atom_tab(atom_val(ep->info.mfa.function)); + long tdcount; + int tres; PRINT_STRING(res, fn, arg, "fun "); - PRINT_BUF(res, fn, arg, module->name, module->len); + + /* We pass a temporary 'dcount' and adjust the real one later to ensure + * that the fun doesn't get split up between the module and function + * name. */ + tdcount = MAX_ATOM_SZ_LIMIT; + tres = print_atom_name(fn, arg, ep->info.mfa.module, &tdcount); + if (tres < 0) { + res = tres; + goto L_done; + } + *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); + res += tres; + PRINT_CHAR(res, fn, arg, ':'); - PRINT_BUF(res, fn, arg, name->name, name->len); + + tdcount = MAX_ATOM_SZ_LIMIT; + tres = print_atom_name(fn, arg, ep->info.mfa.function, &tdcount); + if (tres < 0) { + res = tres; + goto L_done; + } + *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); + res += tres; + PRINT_CHAR(res, fn, arg, '/'); PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) ep->info.mfa.arity); diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 2cbde621ce..ad8ef0feff 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -27,7 +27,7 @@ fun_to_port/1,t_phash/1,t_phash2/1,md5/1, refc/1,refc_ets/1,refc_dist/1, const_propagation/1,t_arity/1,t_is_function2/1, - t_fun_info/1,t_fun_info_mfa/1]). + t_fun_info/1,t_fun_info_mfa/1,t_fun_to_list/1]). -export([nothing/0]). @@ -44,7 +44,7 @@ all() -> equality, ordering, fun_to_port, t_phash, t_phash2, md5, refc, refc_ets, refc_dist, const_propagation, t_arity, t_is_function2, t_fun_info, - t_fun_info_mfa]. + t_fun_info_mfa,t_fun_to_list]. %% Test that the correct EXIT code is returned for all types of bad funs. bad_apply(Config) when is_list(Config) -> @@ -802,6 +802,12 @@ t_fun_info_mfa(Config) when is_list(Config) -> {'EXIT',_} = (catch erlang:fun_info_mfa(id(d))), ok. +t_fun_to_list(Config) when is_list(Config) -> + "fun a:b/1" = erlang:fun_to_list(fun a:b/1), + "fun 'a-esc':'b-esc'/1" = erlang:fun_to_list(fun 'a-esc':'b-esc'/1), + "fun 'a-esc':b/1" = erlang:fun_to_list(fun 'a-esc':b/1), + "fun a:'b-esc'/1" = erlang:fun_to_list(fun a:'b-esc'/1), + ok. bad_info(Term) -> try erlang:fun_info(Term, module) of diff --git a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc index ffbbdadec0..968e89a745 100644 --- a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc @@ -295,7 +295,7 @@ ok</pre> if the log is large. Notice that the <c>Mnesia</c> system continues to operate during log dumps.</p> <p>By default <c>Mnesia</c> either dumps the log whenever - 100 records have + 1000 records have been written in the log or when three minutes have passed. This is controlled by the two application parameters <c>-mnesia dump_log_write_threshold WriteOperations</c> and diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 882de0d613..0f221b0c1f 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -331,35 +331,39 @@ release_schema_commit_lock() -> %% Special for preparation of add table copy get_network_copy(Tid, Tab, Cs) -> -% We can't let the controller queue this one -% because that may cause a deadlock between schema_operations -% and initial tableloadings which both takes schema locks. -% But we have to get copier_done msgs when the other side -% goes down. - call({add_other, self()}), - Reason = {dumper,{add_table_copy, Tid}}, - Work = #net_load{table = Tab,reason = Reason,cstruct = Cs}, - %% I'll need this cause it's linked trough the subscriber - %% might be solved by using monitor in subscr instead. - process_flag(trap_exit, true), - Load = load_table_fun(Work), - Res = ?CATCH(Load()), - process_flag(trap_exit, false), - call({del_other, self()}), - case Res of - #loader_done{is_loaded = true} -> - Tab = Res#loader_done.table_name, - case Res#loader_done.needs_announce of - true -> - i_have_tab(Tab); - false -> - ignore - end, - Res#loader_done.reply; - #loader_done{} -> - Res#loader_done.reply; - Else -> - {not_loaded, Else} + %% We can't let the controller queue this one + %% because that may cause a deadlock between schema_operations + %% and initial tableloadings which both takes schema locks. + %% But we have to get copier_done msgs when the other side + %% goes down. + case call({add_other, self()}) of + ok -> + Reason = {dumper,{add_table_copy, Tid}}, + Work = #net_load{table = Tab,reason = Reason,cstruct = Cs}, + %% I'll need this cause it's linked trough the subscriber + %% might be solved by using monitor in subscr instead. + process_flag(trap_exit, true), + Load = load_table_fun(Work), + Res = ?CATCH(Load()), + process_flag(trap_exit, false), + call({del_other, self()}), + case Res of + #loader_done{is_loaded = true} -> + Tab = Res#loader_done.table_name, + case Res#loader_done.needs_announce of + true -> + i_have_tab(Tab); + false -> + ignore + end, + Res#loader_done.reply; + #loader_done{} -> + Res#loader_done.reply; + Else -> + {not_loaded, Else} + end; + {error, Else} -> + {not_loaded, Else} end. %% This functions is invoked from the dumper @@ -772,6 +776,18 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) -> noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]}) end; +handle_call({add_other, Who}, _From, State = #state{others=Others0, schema_is_merged=SM}) -> + case SM of + true -> + Others = [Who|Others0], + {reply, ok, State#state{others=Others}}; + false -> + {reply, {error, {not_active,schema,node()}}, State} + end; +handle_call({del_other, Who}, _From, State = #state{others=Others0}) -> + Others = lists:delete(Who, Others0), + {reply, ok, State#state{others=Others}}; + handle_call(Msg, From, State) when State#state.schema_is_merged /= true -> %% Buffer early messages Msgs = State#state.early_msgs, @@ -803,13 +819,6 @@ handle_call({block_table, [Tab], From}, _Dummy, State) -> handle_call({check_w2r, _Node, Tab}, _From, State) -> {reply, val({Tab, where_to_read}), State}; -handle_call({add_other, Who}, _From, State = #state{others=Others0}) -> - Others = [Who|Others0], - {reply, ok, State#state{others=Others}}; -handle_call({del_other, Who}, _From, State = #state{others=Others0}) -> - Others = lists:delete(Who, Others0), - {reply, ok, State#state{others=Others}}; - handle_call(Msg, _From, State) -> error("~p got unexpected call: ~tp~n", [?SERVER_NAME, Msg]), noreply(State). diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index f68626413e..0222c5b1a0 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -774,10 +774,12 @@ do_sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) -> N = node(), receive {?MODULE, N, granted} -> + ?ets_insert(Store, {sticky, true}), ?ets_insert(Store, {{locks, Tab, Key}, write}), [?ets_insert(Store, {nodes, Node}) || Node <- WNodes], granted; {?MODULE, N, {granted, Val}} -> %% for rwlocks + ?ets_insert(Store, {sticky, true}), case opt_lookup_in_client(Val, Oid, write) of C = #cyclic{} -> exit({aborted, C}); diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index 4cfe16dec0..4e50b46da8 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -83,9 +83,9 @@ going_down = [], tm_started = false, early_connects = [], connecting, mq = [], remote_node_status = []}). --define(current_protocol_version, {8,3}). +-define(current_protocol_version, {8,4}). --define(previous_protocol_version, {8,2}). +-define(previous_protocol_version, {8,3}). start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, @@ -196,7 +196,7 @@ protocol_version() -> %% A sorted list of acceptable protocols the %% preferred protocols are first in the list acceptable_protocol_versions() -> - [protocol_version(), ?previous_protocol_version, {8,1}]. + [protocol_version(), ?previous_protocol_version]. needs_protocol_conversion(Node) -> case {?catch_val({protocol, Node}), protocol_version()} of diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index ef38adca1e..d0f5d0e07b 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -697,7 +697,7 @@ schema_coordinator(Client, _Fun, undefined) -> schema_coordinator(Client, Fun, Controller) when is_pid(Controller) -> %% Do not trap exit in order to automatically die %% when the controller dies - + put(transaction_client, Client), %% debug link(Controller), unlink(Client), @@ -730,7 +730,10 @@ api_list2cs(Other) -> mnesia:abort({badarg, Other}). vsn_cs2list(Cs) -> - cs2list(need_old_cstructs(), Cs). + cs2list(Cs). + +cs2list(false, Cs) -> + cs2list(Cs). cs2list(Cs) when is_record(Cs, cstruct) -> Tags = record_info(fields, cstruct), @@ -755,25 +758,6 @@ cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 19 -> cookie,version], rec2list(Tags, Tags, 2, Cs). -cs2list(false, Cs) -> - cs2list(Cs); -cs2list({8,3}, Cs) -> - cs2list(Cs); -cs2list({8,Minor}, Cs) when Minor =:= 2; Minor =:= 1 -> - Orig = record_info(fields, cstruct), - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,majority,index,snmp,local_content, - record_name,attributes, - user_properties,frag_properties,storage_properties, - cookie,version], - CsList = rec2list(Tags, Orig, 2, Cs), - case proplists:get_value(index, CsList, []) of - [] -> CsList; - NewFormat -> - OldFormat = [Pos || {Pos, _Pref} <- NewFormat], - lists:keyreplace(index, 1, CsList, {index, OldFormat}) - end. - rec2list([index | Tags], [index|Orig], Pos, Rec) -> Val = element(Pos, Rec), [{index, lists:map( @@ -796,19 +780,8 @@ rec2list([], _, _Pos, _Rec) -> rec2list(Tags, [_|Orig], Pos, Rec) -> rec2list(Tags, Orig, Pos+1, Rec). -normalize_cs(Cstructs, Node) -> - %% backward-compatibility hack; normalize before returning - case need_old_cstructs([Node]) of - false -> - Cstructs; - Version -> - %% some other format - [convert_cs(Version, Cs) || Cs <- Cstructs] - end. - -convert_cs(Version, Cs) -> - Fields = [Value || {_, Value} <- cs2list(Version, Cs)], - list_to_tuple([cstruct|Fields]). +normalize_cs(Cstructs, _Node) -> + Cstructs. list2cs(List) -> list2cs(List, get_ext_types()). @@ -1864,11 +1837,7 @@ do_move_table(schema, _FromNode, _ToNode) -> mnesia:abort({bad_type, schema}); do_move_table(Tab, FromNode, ToNode) when is_atom(FromNode), is_atom(ToNode) -> TidTs = get_tid_ts_and_lock(schema, write), - AnyOld = lists:any(fun(Node) -> mnesia_monitor:needs_protocol_conversion(Node) end, - [ToNode|val({Tab, where_to_write})]), - if AnyOld -> ignore; %% Leads to deadlock on old nodes - true -> get_tid_ts_and_lock(Tab, write) - end, + get_tid_ts_and_lock(Tab, write), insert_schema_ops(TidTs, make_move_table(Tab, FromNode, ToNode)); do_move_table(Tab, FromNode, ToNode) -> mnesia:abort({badarg, Tab, FromNode, ToNode}). @@ -3438,15 +3407,14 @@ do_merge_schema(LockTabs0) -> mnesia_lib:intersect(Ns,NeedsLock)) || {T,Ns} <- LockTabs], - NeedsConversion = need_old_cstructs(NeedsLock ++ LockedAlready), {value, SchemaCs} = lists:keysearch(schema, #cstruct.name, Cstructs), - SchemaDef = cs2list(NeedsConversion, SchemaCs), + SchemaDef = cs2list(false, SchemaCs), %% Announce that Node is running A = [{op, announce_im_running, node(), SchemaDef, Running, RemoteRunning}], do_insert_schema_ops(Store, A), %% Introduce remote tables to local node - do_insert_schema_ops(Store, make_merge_schema(Node, NeedsConversion, Cstructs)), + do_insert_schema_ops(Store, make_merge_schema(Node, false, Cstructs)), %% Introduce local tables to remote nodes Tabs = val({schema, tables}), @@ -3471,23 +3439,7 @@ do_merge_schema(LockTabs0) -> end. fetch_cstructs(Node) -> - Convert = mnesia_monitor:needs_protocol_conversion(Node), - case rpc:call(Node, mnesia_controller, get_remote_cstructs, []) of - {cstructs, Cs0, RemoteRunning1} when Convert -> - {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RemoteRunning1}; - Result -> - Result - end. - -need_old_cstructs() -> - need_old_cstructs(val({schema, where_to_write})). - -need_old_cstructs(Nodes) -> - Filter = fun(Node) -> mnesia_monitor:needs_protocol_conversion(Node) end, - case lists:filter(Filter, Nodes) of - [] -> false; - Ns -> lists:min([element(1, ?catch_val({protocol, Node})) || Node <- Ns]) - end. + rpc:call(Node, mnesia_controller, get_remote_cstructs, []). tab_to_nodes(Tab) when is_atom(Tab) -> Cs = val({Tab, cstruct}), diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index 8b79fca1d7..8a4113422a 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -26,7 +26,7 @@ init/1, non_transaction/5, transaction/6, - commit_participant/5, + commit_participant/6, dirty/2, display_info/2, do_update_op/3, @@ -62,13 +62,14 @@ %% Format on coordinators is [{Tid, EtsTabList} ..... -record(prep, {protocol = sym_trans, - %% async_dirty | sync_dirty | sym_trans | sync_sym_trans | asym_trans + %% async_dirty | sync_dirty | sym_trans | sync_sym_trans | asym_trans | sync_asym_trans records = [], prev_tab = [], % initiate to a non valid table name prev_types, prev_snmp, types, - majority = [] + majority = [], + sync = false }). -record(participant, {tid, pid, commit, disc_nodes = [], @@ -250,11 +251,13 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), Commit = new_cr_format(Commit0), Pid = - case Protocol of - asym_trans when node(Tid#tid.pid) /= node() -> - Args = [tmpid(From), Tid, Commit, DiscNs, RamNs], + if + node(Tid#tid.pid) =:= node() -> + error({internal_error, local_node}); + Protocol =:= asym_trans orelse Protocol =:= sync_asym_trans -> + Args = [Protocol, tmpid(From), Tid, Commit, DiscNs, RamNs], spawn_link(?MODULE, commit_participant, Args); - _ when node(Tid#tid.pid) /= node() -> %% *_sym_trans + true -> %% *_sym_trans reply(From, {vote_yes, Tid}), nopid end, @@ -1190,7 +1193,15 @@ do_arrange(Tid, Store, RestoreKey, Prep, N) when RestoreKey == restore_op -> P2 = Prep#prep{protocol = asym_trans, records = Recs2}, do_arrange(Tid, Store, ?ets_next(Store, RestoreKey), P2, N + 1); do_arrange(_Tid, _Store, '$end_of_table', Prep, N) -> - {N, Prep}; + case Prep of + #prep{sync=true, protocol=asym_trans} -> + {N, Prep#prep{protocol=sync_asym_trans}}; + _ -> + {N, Prep} + end; +do_arrange(Tid, Store, sticky, Prep, N) -> + P2 = Prep#prep{sync=true}, + do_arrange(Tid, Store, ?ets_next(Store, sticky), P2, N); do_arrange(Tid, Store, IgnoredKey, Prep, N) -> %% locks, nodes ... local atoms... do_arrange(Tid, Store, ?ets_next(Store, IgnoredKey), Prep, N). @@ -1448,7 +1459,8 @@ multi_commit(sync_sym_trans, _Maj = [], Tid, CR, Store) -> [{tid, Tid}, {outcome, Outcome}]), Outcome; -multi_commit(asym_trans, Majority, Tid, CR, Store) -> +multi_commit(Protocol, Majority, Tid, CR, Store) + when Protocol =:= asym_trans; Protocol =:= sync_asym_trans -> %% This more expensive commit protocol is used when %% table definitions are changed (schema transactions). %% It is also used when the involved tables are @@ -1515,7 +1527,7 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> end, Pending = mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), ?ets_insert(Store, Pending), - {WaitFor, Local} = ask_commit(asym_trans, Tid, CR2, DiscNs, RamNs), + {WaitFor, Local} = ask_commit(Protocol, Tid, CR2, DiscNs, RamNs), SchemaPrep = ?CATCH(mnesia_schema:prepare_commit(Tid, Local, {coord, WaitFor})), {Votes, Pids} = rec_all(WaitFor, Tid, do_commit, []), @@ -1563,38 +1575,38 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> %% Returns do_commit or {do_abort, Reason} rec_acc_pre_commit([Pid | Tail], Tid, Store, Commit, Res, DumperMode, - GoodPids, SchemaAckPids) -> + GoodPids, AckPids) -> receive {?MODULE, _, {acc_pre_commit, Tid, Pid, true}} -> rec_acc_pre_commit(Tail, Tid, Store, Commit, Res, DumperMode, - [Pid | GoodPids], [Pid | SchemaAckPids]); + [Pid | GoodPids], [Pid | AckPids]); {?MODULE, _, {acc_pre_commit, Tid, Pid, false}} -> rec_acc_pre_commit(Tail, Tid, Store, Commit, Res, DumperMode, - [Pid | GoodPids], SchemaAckPids); + [Pid | GoodPids], AckPids); {?MODULE, _, {acc_pre_commit, Tid, Pid}} -> %% Kept for backwards compatibility. Remove after Mnesia 4.x rec_acc_pre_commit(Tail, Tid, Store, Commit, Res, DumperMode, - [Pid | GoodPids], [Pid | SchemaAckPids]); + [Pid | GoodPids], [Pid | AckPids]); {?MODULE, _, {do_abort, Tid, Pid, _Reason}} -> AbortRes = {do_abort, {bad_commit, node(Pid)}}, rec_acc_pre_commit(Tail, Tid, Store, Commit, AbortRes, DumperMode, - GoodPids, SchemaAckPids); + GoodPids, AckPids); {mnesia_down, Node} when Node == node(Pid) -> AbortRes = {do_abort, {bad_commit, Node}}, ?SAFE(Pid ! {Tid, AbortRes}), %% Tell him that he has died rec_acc_pre_commit(Tail, Tid, Store, Commit, AbortRes, DumperMode, - GoodPids, SchemaAckPids) + GoodPids, AckPids) end; -rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, SchemaAckPids) -> +rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, AckPids) -> D = Commit#commit.decision, case Res of do_commit -> %% Now everybody knows that the others %% has voted yes. We also know that %% everybody are uncertain. - prepare_sync_schema_commit(Store, SchemaAckPids), + prepare_sync_schema_commit(Store, AckPids), tell_participants(GoodPids, {Tid, committed}), D2 = D#decision{outcome = committed}, mnesia_recover:log_decision(D2), @@ -1606,7 +1618,7 @@ rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, Sc do_commit(Tid, Commit, DumperMode), ?eval_debug_fun({?MODULE, rec_acc_pre_commit_done_commit}, [{tid, Tid}]), - sync_schema_commit(Tid, Store, SchemaAckPids), + sync_schema_commit(Tid, Store, AckPids), mnesia_locker:release_tid(Tid), ?MODULE ! {delete_transaction, Tid}; @@ -1623,6 +1635,7 @@ rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, Sc Res. %% Note all nodes in case of mnesia_down mgt +%% sync_schema_commit is (ab)used for sync_asym_trans as well. prepare_sync_schema_commit(_Store, []) -> ok; prepare_sync_schema_commit(Store, [Pid | Pids]) -> @@ -1648,17 +1661,17 @@ tell_participants([Pid | Pids], Msg) -> tell_participants([], _Msg) -> ok. --spec commit_participant(_, _, _, _, _) -> no_return(). +-spec commit_participant(_, _, _, _, _, _) -> no_return(). %% Trap exit because we can get a shutdown from application manager -commit_participant(Coord, Tid, Bin, DiscNs, RamNs) when is_binary(Bin) -> +commit_participant(Protocol, Coord, Tid, Bin, DiscNs, RamNs) when is_binary(Bin) -> process_flag(trap_exit, true), Commit = binary_to_term(Bin), - commit_participant(Coord, Tid, Bin, Commit, DiscNs, RamNs); -commit_participant(Coord, Tid, C = #commit{}, DiscNs, RamNs) -> + commit_participant(Protocol, Coord, Tid, Bin, Commit, DiscNs, RamNs); +commit_participant(Protocol, Coord, Tid, C = #commit{}, DiscNs, RamNs) -> process_flag(trap_exit, true), - commit_participant(Coord, Tid, C, C, DiscNs, RamNs). + commit_participant(Protocol, Coord, Tid, C, C, DiscNs, RamNs). -commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> +commit_participant(Protocol, Coord, Tid, Bin, C0, DiscNs, _RamNs) -> ?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]), try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of {Modified, C = #commit{}, DumperMode} -> @@ -1683,8 +1696,9 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> mnesia_recover:log_decision(D#decision{outcome = unclear}), ?eval_debug_fun({?MODULE, commit_participant, pre_commit}, [{tid, Tid}]), - Expect_schema_ack = C#commit.schema_ops /= [], - reply(Coord, {acc_pre_commit, Tid, self(), Expect_schema_ack}), + ExpectAck = C#commit.schema_ops /= [] + orelse Protocol =:= sync_asym_trans, + reply(Coord, {acc_pre_commit, Tid, self(), ExpectAck}), %% Now we are vulnerable for failures, since %% we cannot decide without asking others @@ -1694,7 +1708,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> ?eval_debug_fun({?MODULE, commit_participant, log_commit}, [{tid, Tid}]), do_commit(Tid, C, DumperMode), - case Expect_schema_ack of + case ExpectAck of false -> ignore; true -> reply(Coord, {schema_commit, Tid, self()}) end, @@ -1978,7 +1992,7 @@ sync_send_dirty(Tid, [Head | Tail], Tab, WaitFor) -> Res = do_dirty(Tid, Head), {WF, Res}; true -> - {?MODULE, Node} ! {self(), {sync_dirty, Tid, ext_format(Head), Tab}}, + {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}}, sync_send_dirty(Tid, Tail, Tab, [Node | WaitFor]) end; sync_send_dirty(_Tid, [], _Tab, WaitFor) -> @@ -1997,11 +2011,11 @@ async_send_dirty(Tid, [Head | Tail], Tab, ReadNode, WaitFor, Res) -> NewRes = do_dirty(Tid, Head), async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, NewRes); ReadNode == Node -> - {?MODULE, Node} ! {self(), {sync_dirty, Tid, ext_format(Head), Tab}}, + {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}}, NewRes = {'EXIT', {aborted, {node_not_running, Node}}}, async_send_dirty(Tid, Tail, Tab, ReadNode, [Node | WaitFor], NewRes); true -> - {?MODULE, Node} ! {self(), {async_dirty, Tid, ext_format(Head), Tab}}, + {?MODULE, Node} ! {self(), {async_dirty, Tid, Head, Tab}}, async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, Res) end; async_send_dirty(_Tid, [], _Tab, _ReadNode, WaitFor, Res) -> @@ -2058,24 +2072,20 @@ ask_commit(Protocol, Tid, [Head | Tail], DiscNs, RamNs, WaitFor, Local) -> Node == node() -> ask_commit(Protocol, Tid, Tail, DiscNs, RamNs, WaitFor, Head); true -> - CR = ext_format(Head), - Msg = {ask_commit, Protocol, Tid, CR, DiscNs, RamNs}, + Msg = {ask_commit, convert_old(Protocol, Node), Tid, Head, DiscNs, RamNs}, {?MODULE, Node} ! {self(), Msg}, ask_commit(Protocol, Tid, Tail, DiscNs, RamNs, [Node | WaitFor], Local) end; ask_commit(_Protocol, _Tid, [], _DiscNs, _RamNs, WaitFor, Local) -> {WaitFor, Local}. -ext_format(#commit{ext=[]}=CR) -> CR; -ext_format(#commit{node=Node, ext=Ext}=CR) -> +convert_old(sync_asym_trans, Node) -> case mnesia_monitor:needs_protocol_conversion(Node) of - true -> - case lists:keyfind(snmp, 1, Ext) of - false -> CR#commit{ext=[]}; - {snmp, List} -> CR#commit{ext=List} - end; - false -> CR - end. + true -> asym_trans; + false -> sync_asym_trans + end; +convert_old(Protocol, _) -> + Protocol. new_cr_format(#commit{ext=[]}=Cr) -> Cr; new_cr_format(#commit{ext=[{_,_}|_]}=Cr) -> Cr; @@ -2304,7 +2314,7 @@ reconfigure_participants(_, []) -> %% tell mnesia_tm on all involved nodes (including the local node) %% about the outcome. tell_outcome(Tid, Protocol, Node, CheckNodes, TellNodes) -> - Outcome = mnesia_recover:what_happened(Tid, Protocol, CheckNodes), + Outcome = mnesia_recover:what_happened(Tid, proto(Protocol), CheckNodes), case Outcome of aborted -> rpc:abcast(TellNodes, ?MODULE, {Tid,{do_abort, {mnesia_down, Node}}}); @@ -2313,6 +2323,9 @@ tell_outcome(Tid, Protocol, Node, CheckNodes, TellNodes) -> end, Outcome. +proto(sync_asym_trans) -> asym_trans; +proto(Proto) -> Proto. + do_stop(#state{coordinators = Coordinators}) -> Msg = {mnesia_down, node()}, lists:foreach(fun({Tid, _}) -> Tid#tid.pid ! Msg end, gb_trees:to_list(Coordinators)), diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 49bcec14af..c99158945d 100644 --- a/lib/mnesia/test/mnesia_isolation_test.erl +++ b/lib/mnesia/test/mnesia_isolation_test.erl @@ -29,7 +29,7 @@ -export([no_conflict/1, simple_queue_conflict/1, advanced_queue_conflict/1, simple_deadlock_conflict/1, advanced_deadlock_conflict/1, schema_deadlock/1, lock_burst/1, - nasty/1, basic_sticky_functionality/1, + nasty/1, basic_sticky_functionality/1, sticky_sync/1, unbound1/1, unbound2/1, create_table/1, delete_table/1, move_table_copy/1, add_table_index/1, del_table_index/1, transform_table/1, @@ -71,7 +71,8 @@ groups() -> advanced_deadlock_conflict, schema_deadlock, lock_burst, {group, sticky_locks}, {group, unbound_locking}, {group, admin_conflict}, nasty]}, - {sticky_locks, [], [basic_sticky_functionality]}, + {sticky_locks, [], + [basic_sticky_functionality,sticky_sync]}, {unbound_locking, [], [unbound1, unbound2]}, {admin_conflict, [], [create_table, delete_table, move_table_copy, @@ -594,9 +595,49 @@ get_held() -> mnesia_locker ! {get_table, self(), mnesia_sticky_locks}, receive {mnesia_sticky_locks, Locks} -> Locks end. +sticky_sync(suite) -> []; +sticky_sync(Config) when is_list(Config) -> + %% BUG ERIERL-768 + Nodes = [N1, N2] = ?acquire_nodes(2, Config), + + mnesia:create_table(dc, [{type, ordered_set}, {disc_copies, Nodes}]), + mnesia:create_table(ec, [{type, ordered_set}, {ram_copies, [N2]}]), + + TestFun = + fun(I) -> + %% In first transaction we initialise {dc, I} record with value 0 + First = fun() -> + %% Do a lot of writes into ram copies table + %% which on the Slave in do_commit will be + %% processed first + lists:foreach(fun(J) -> ok = mnesia:write(ec, {ec, J, 0}, write) end, + lists:seq(1, 750)), + %% Then set initial value of {dc, I} record to 0 with sticky_write + mnesia:write(dc, {dc, I, 0}, sticky_write) + end, + ok = mnesia:activity(transaction, First), + %% In second transaction we set value of {dc, I} record to 1 + Upd = fun() -> + %% Modify a single ram copies record with ensured lock grant + %% (key not used in previous transactions) + %% we use this second table only to force asym_trans protocol + mnesia:write(ec, {ec, 1001 + I, 0}, write), + %% And set final version of {dc, I} record to 1 with sticky_write + mnesia:write(dc, {dc, I, 1}, sticky_write) + end, + ok = mnesia:activity(transaction, Upd) + end, + + %% Fill 1000 dc records. At the end all dc records should have value 1. + lists:foreach(TestFun, lists:seq(1,1000)), + io:format("Written, check content~n",[]), + All = fun() -> mnesia:select(dc, [ {{dc, '_', 0}, [] ,['$_']} ]) end, + ?match({atomic, []}, rpc:call(N1, mnesia, sync_transaction, [All])), + ?match({atomic, []}, rpc:call(N2, mnesia, sync_transaction, [All])), -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ?verify_mnesia(Nodes, []). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unbound1(suite) -> []; unbound1(Config) when is_list(Config) -> @@ -1036,29 +1077,57 @@ add_table_copy(Config) when is_list(Config) -> Def = [{ram_copies, [ThisNode]}, {attributes, [key, attr1, attr2]}], ?match({atomic, ok}, mnesia:create_table(Tab, Def)), insert(Tab, 50), - {success, [A]} = ?start_activities([ThisNode]), + {success, [A]} = ?start_activities([ThisNode]), mnesia_test_lib:start_sync_transactions([A], 0), A ! fun() -> mnesia:write({Tab, 1, 1, updated}) end, ?match_receive({A, ok}), %% A is executed - Pid = spawn_link(?MODULE, op, [self(), mnesia, add_table_copy, + Pid = spawn_link(?MODULE, op, [self(), mnesia, add_table_copy, [Tab, Node2, ram_copies]]), - + ?match_receive(timeout), %% op waits for locks occupied by A A ! end_trans, %% Kill A, locks should be released - ?match_receive({A,{atomic,end_trans}}), - - receive + ?match_receive({A,{atomic,end_trans}}), + + receive Msg -> ?match({Pid, {atomic, ok}}, Msg) after timer:seconds(20) -> ?error("Operation timed out", []) end, + ?match_receive({'EXIT', Pid, normal}), sys:get_status(whereis(mnesia_locker)), % Explicit sync, release locks is async - ?match([], mnesia:system_info(held_locks)), - ?match([], mnesia:system_info(lock_queue)), + ?match([], mnesia:system_info(held_locks)), + ?match([], mnesia:system_info(lock_queue)), + + {atomic, ok} = mnesia:del_table_copy(Tab, Node2), + Self = self(), + New = spawn_link(Node2, + fun () -> + application:stop(mnesia), + Self ! {self(), ok}, + io:format(user, "restart mnesia~n", []), + Self ! {self(), catch application:start(mnesia)} + end), + receive {New,ok} -> ok end, + + Add = fun Add() -> + case mnesia:add_table_copy(Tab, Node2, disc_copies) of + {atomic, ok} -> ok; + _R -> io:format(user, "aborted with reason ~p~n", [_R]), + timer:sleep(10), + Add() + end + end, + + ?match(ok, Add()), + ?match_receive({New,ok}), + + sys:get_status(whereis(mnesia_locker)), % Explicit sync, release locks is async + ?match([], mnesia:system_info(held_locks)), + ?match([], mnesia:system_info(lock_queue)), ok. del_table_copy(suite) -> []; diff --git a/lib/mnesia/test/mt b/lib/mnesia/test/mt index a398ee0422..b169734f56 100755 --- a/lib/mnesia/test/mt +++ b/lib/mnesia/test/mt @@ -34,8 +34,35 @@ erlcmd="erl -sname a $p $args -mnesia_test_timeout" erlcmd1="erl -sname a1 $p $args" erlcmd2="erl -sname a2 $p $args" -xterm -geometry 70x20+0+550 -T a1 -e $erlcmd1 & -xterm -geometry 70x20+450+550 -T a2 -e $erlcmd2 & +if test z"$MT_TERM" = z ; then + MT_TERM=xterm +fi + +case $MT_TERM in + xterm) + geom0="-geometry 142x40+0+0" + geom1="-geometry 70x20+0+550" + geom2="-geometry 70x20+480+550" + title="-T" + exec="-e" + ;; + gnome-terminal) + geom0="--geometry 142x40+0+0" + geom1="--geometry 70x20+0+740" + geom2="--geometry 70x20+700+740" + title="--title" + exec="--hide-menubar --" + ;; + *rxvt) + geom0="-geometry 142x40+0+0" + geom1="-geometry 70x20+0+680" + geom2="-geometry 70x20+630+680" + title="-title" + exec="-e" +esac + +$MT_TERM $geom1 $title a1 $exec $erlcmd1 & +$MT_TERM $geom2 $title a2 $exec $erlcmd2 & rm "$latest" 2>/dev/null ln -s "$log" "$latest" @@ -51,11 +78,6 @@ echo "Give the following command in order to see the outcome from node a@$h"":" echo "" echo " less test_log$$" -ostype=`uname -s` -if [ "$ostype" = "SunOS" ] ; then - /usr/openwin/bin/xterm -geometry 145x40+0+0 -T a -l -lf "$log" -e $erlcmd & -else - xterm -geometry 145x40+0+0 -T a -e script -f -c "$erlcmd" "$log" & -fi +$MT_TERM $geom0 $title a $exec script -f -c "$erlcmd" "$log" & tail -f "$log" | egrep 'Eval|<>ERROR|NYI' diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl index 91d33474c8..819596b483 100644 --- a/lib/observer/src/cdv_bin_cb.erl +++ b/lib/observer/src/cdv_bin_cb.erl @@ -33,42 +33,43 @@ detail_pages() -> [{"Binary", fun init_bin_page/2}]. init_bin_page(Parent,{Type,Bin}) -> + Cs = observer_lib:colors(Parent), cdv_multi_wx:start_link( Parent, - [{"Format \~p",cdv_html_wx,{Type,format_bin_fun("~p",Bin)}}, - {"Format \~tp",cdv_html_wx,{Type,format_bin_fun("~tp",Bin)}}, - {"Format \~w",cdv_html_wx,{Type,format_bin_fun("~w",Bin)}}, - {"Format \~tw",cdv_html_wx,{Type,format_bin_fun("~tw",Bin)}}, - {"Format \~s",cdv_html_wx,{Type,format_bin_fun("~s",Bin)}}, - {"Format \~ts",cdv_html_wx,{Type,format_bin_fun("~ts",Bin)}}, - {"Hex",cdv_html_wx,{Type,hex_binary_fun(Bin)}}, - {"Term",cdv_html_wx,{Type,binary_to_term_fun(Bin)}}]). + [{"Format \~p",cdv_html_wx,{Type,format_bin_fun("~p",Bin,Cs)}}, + {"Format \~tp",cdv_html_wx,{Type,format_bin_fun("~tp",Bin,Cs)}}, + {"Format \~w",cdv_html_wx,{Type,format_bin_fun("~w",Bin,Cs)}}, + {"Format \~tw",cdv_html_wx,{Type,format_bin_fun("~tw",Bin,Cs)}}, + {"Format \~s",cdv_html_wx,{Type,format_bin_fun("~s",Bin,Cs)}}, + {"Format \~ts",cdv_html_wx,{Type,format_bin_fun("~ts",Bin,Cs)}}, + {"Hex",cdv_html_wx,{Type,hex_binary_fun(Bin,Cs)}}, + {"Term",cdv_html_wx,{Type,binary_to_term_fun(Bin,Cs)}}]). -format_bin_fun(Format,Bin) -> +format_bin_fun(Format,Bin,Cs) -> fun() -> try io_lib:format(Format,[Bin]) of - Str -> plain_html(lists:flatten(Str)) + Str -> plain_html(lists:flatten(Str),Cs) catch error:badarg -> Warning = "This binary cannot be formatted with " ++ Format, - observer_html_lib:warning(Warning) + observer_html_lib:warning(Warning,Cs) end end. -binary_to_term_fun(Bin) -> +binary_to_term_fun(Bin,Cs) -> fun() -> try binary_to_term(Bin) of - Term -> plain_html(io_lib:format("~tp",[Term])) + Term -> plain_html(io_lib:format("~tp",[Term]),Cs) catch error:badarg -> Warning = "This binary cannot be converted to an Erlang term", - observer_html_lib:warning(Warning) + observer_html_lib:warning(Warning,Cs) end end. -define(line_break,25). -hex_binary_fun(Bin) -> +hex_binary_fun(Bin,Cs) -> fun() -> S = "<<" ++ format_hex(Bin,?line_break) ++ ">>", - plain_html(io_lib:format("~s",[S])) + plain_html(io_lib:format("~s",[S]), Cs) end. format_hex(<<>>,_) -> @@ -82,5 +83,5 @@ format_hex(<<B1:4,B2:4,Bin/binary>>,N) -> [integer_to_list(B1,16),integer_to_list(B2,16),$, | format_hex(Bin,N-1)]. -plain_html(Text) -> - observer_html_lib:plain_page(Text). +plain_html(Text,Cs) -> + observer_html_lib:plain_page(Text,Cs). diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl index 8956173c93..83ee98de6e 100644 --- a/lib/observer/src/cdv_html_wx.erl +++ b/lib/observer/src/cdv_html_wx.erl @@ -30,7 +30,8 @@ %% Records -record(state, - {panel, + {parent, + panel, app, %% which tool is the user expand_table, expand_wins=[], @@ -62,7 +63,7 @@ init(ParentWin, HtmlText, Tab, App) -> HtmlWin = observer_lib:html_window(ParentWin), wxHtmlWindow:setPage(HtmlWin,HtmlText), wx_misc:endBusyCursor(), - {HtmlWin, #state{panel=HtmlWin,expand_table=Tab,app=App}}. + {HtmlWin, #state{parent=ParentWin, panel=HtmlWin,expand_table=Tab,app=App}}. init(ParentWin, Callback) -> {HtmlWin, State} = init(ParentWin, "", undefined, cdv), @@ -70,12 +71,15 @@ init(ParentWin, Callback) -> %%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -handle_info(active, #state{panel=HtmlWin,delayed_fetch=Callback}=State) +handle_info(active, #state{parent=Parent, panel=HtmlWin,delayed_fetch=Callback}=State) when Callback=/=undefined -> observer_lib:display_progress_dialog(HtmlWin, "Crashdump Viewer", "Reading data"), - {{expand,HtmlText,Tab},TW} = Callback:get_info(), + {{expand,Title,Info,Tab},TW} = Callback:get_info(), + Cs = observer_lib:colors(Parent), + HtmlText = observer_html_lib:expandable_term(Title,Info,Tab,Cs), + observer_lib:sync_destroy_progress_dialog(), wx_misc:beginBusyCursor(), wxHtmlWindow:setPage(HtmlWin,HtmlText), @@ -138,7 +142,8 @@ handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked, list_to_integer(Key3)}}}, expand(Id,cdv_term_cb,State); _ when App =:= obs -> - observer ! {open_link, Target}; + observer ! {open_link, Target}, + State; _ -> cdv_virtual_list_wx:start_detail_win(Target), State diff --git a/lib/observer/src/cdv_mod_cb.erl b/lib/observer/src/cdv_mod_cb.erl index 2183e1aa3d..7f2cd0cf87 100644 --- a/lib/observer/src/cdv_mod_cb.erl +++ b/lib/observer/src/cdv_mod_cb.erl @@ -85,7 +85,8 @@ init_old_comp_page(Parent, Info) -> init_info_page(Parent, undefined) -> init_info_page(Parent, ""); init_info_page(Parent, String) -> - cdv_html_wx:start_link(Parent,observer_html_lib:plain_page(String)). + Cs = observer_lib:colors(Parent), + cdv_html_wx:start_link(Parent,observer_html_lib:plain_page(String,Cs)). format({Bin,q}) when is_binary(Bin) -> [$'|binary_to_list(Bin)]; diff --git a/lib/observer/src/cdv_persistent_cb.erl b/lib/observer/src/cdv_persistent_cb.erl index d5da18f7fc..90abc6a4f5 100644 --- a/lib/observer/src/cdv_persistent_cb.erl +++ b/lib/observer/src/cdv_persistent_cb.erl @@ -26,7 +26,4 @@ get_info() -> Tab = ets:new(pt_expand,[set,public]), {ok,PT,TW} = crashdump_viewer:persistent_terms(), - {{expand, - observer_html_lib:expandable_term("Persistent Terms",PT,Tab), - Tab}, - TW}. + {{expand, "Persistent Terms", PT, Tab}, TW}. diff --git a/lib/observer/src/cdv_proc_cb.erl b/lib/observer/src/cdv_proc_cb.erl index 2497b4889e..61bd86f188 100644 --- a/lib/observer/src/cdv_proc_cb.erl +++ b/lib/observer/src/cdv_proc_cb.erl @@ -108,7 +108,7 @@ init_stack_page(Parent, Info) -> init_memory_page(Parent, Info0, Tag, Heading) -> Info = proplists:get_value(Tag,Info0), Tab = proplists:get_value(expand_table,Info0), - Html = observer_html_lib:expandable_term(Heading,Info,Tab), + Html = observer_html_lib:expandable_term(Heading,Info,Tab, observer_lib:colors(Parent)), cdv_html_wx:start_link(Parent,{expand,Html,Tab}). init_ets_page(Parent, Info) -> diff --git a/lib/observer/src/cdv_term_cb.erl b/lib/observer/src/cdv_term_cb.erl index 85da1d227a..a2a7a8750d 100644 --- a/lib/observer/src/cdv_term_cb.erl +++ b/lib/observer/src/cdv_term_cb.erl @@ -35,31 +35,32 @@ init_term_page(ParentWin, {Type, [Term, Tab]}) -> Expanded = expand(Term, true), BinSaved = expand(Term, Tab), observer_lib:report_progress({ok,stop_pulse}), + Cs = observer_lib:colors(ParentWin), cdv_multi_wx:start_link( ParentWin, - [{"Format \~p",cdv_html_wx,{Type, format_term_fun("~p",BinSaved,Tab)}}, - {"Format \~tp",cdv_html_wx,{Type,format_term_fun("~tp",BinSaved,Tab)}}, - {"Format \~w",cdv_html_wx,{Type,format_term_fun("~w",BinSaved,Tab)}}, - {"Format \~tw",cdv_html_wx,{Type,format_term_fun("~tw",BinSaved,Tab)}}, - {"Format \~s",cdv_html_wx,{Type,format_term_fun("~s",Expanded,Tab)}}, - {"Format \~ts",cdv_html_wx,{Type,format_term_fun("~ts",Expanded,Tab)}}]). + [{"Format \~p",cdv_html_wx,{Type, format_term_fun("~p",BinSaved,Tab,Cs)}}, + {"Format \~tp",cdv_html_wx,{Type,format_term_fun("~tp",BinSaved,Tab,Cs)}}, + {"Format \~w",cdv_html_wx,{Type,format_term_fun("~w",BinSaved,Tab,Cs)}}, + {"Format \~tw",cdv_html_wx,{Type,format_term_fun("~tw",BinSaved,Tab,Cs)}}, + {"Format \~s",cdv_html_wx,{Type,format_term_fun("~s",Expanded,Tab,Cs)}}, + {"Format \~ts",cdv_html_wx,{Type,format_term_fun("~ts",Expanded,Tab,Cs)}}]). -format_term_fun(Format,Term,Tab) -> +format_term_fun(Format,Term,Tab,Cs) -> fun() -> observer_lib:report_progress({ok,"Formatting term"}), observer_lib:report_progress({ok,start_pulse}), try io_lib:format(Format,[Term]) of - Str -> {expand, plain_html(Str), Tab} + Str -> {expand, plain_html(Str,Cs), Tab} catch error:badarg -> Warning = "This term cannot be formatted with " ++ Format, - observer_html_lib:warning(Warning) + observer_html_lib:warning(Warning,Cs) after observer_lib:report_progress({ok,stop_pulse}) end end. -plain_html(Text) -> - observer_html_lib:plain_page(Text). +plain_html(Text,Cs) -> + observer_html_lib:plain_page(Text,Cs). expand(['#CDVBin',Offset,Size,Pos], true) -> {ok,Bin} = crashdump_viewer:expand_binary({Offset,Size,Pos}), diff --git a/lib/observer/src/cdv_virtual_list_wx.erl b/lib/observer/src/cdv_virtual_list_wx.erl index 14877b7eab..51e85e17c1 100644 --- a/lib/observer/src/cdv_virtual_list_wx.erl +++ b/lib/observer/src/cdv_virtual_list_wx.erl @@ -96,8 +96,9 @@ start_detail_win_2(Callback,Id) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init([ParentWin, Callback, Owner]) -> - {Holder,TW} = spawn_table_holder(Callback, Owner), Panel = wxPanel:new(ParentWin), + Attrs = observer_lib:create_attrs(Panel), + {Holder,TW} = spawn_table_holder(Callback, Owner, Attrs), {Grid,MenuCols} = create_list_box(Panel, Holder, Callback, Owner), Sizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL}, @@ -233,7 +234,8 @@ handle_call(new_dump, _From, Ref = erlang:monitor(process,Holder), Holder ! stop, receive {'DOWN',Ref,_,_,_} -> ok end, - {NewHolder,TW} = spawn_table_holder(Callback, all), + Attrs = observer_lib:create_attrs(Grid), + {NewHolder,TW} = spawn_table_holder(Callback, all, Attrs), {reply, ok, State#state{detail_wins=[],holder=NewHolder,trunc_warn=TW}}; handle_call(Msg, _From, State) -> @@ -329,9 +331,8 @@ handle_event(Event, State) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%TABLE HOLDER%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spawn_table_holder(Callback, Owner) -> +spawn_table_holder(Callback, Owner, Attrs) -> {Info,TW} = Callback:get_info(Owner), - Attrs = observer_lib:create_attrs(), Parent = self(), Holder = case Owner of diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl index 7100cc8790..8ad5da857e 100644 --- a/lib/observer/src/cdv_wx.erl +++ b/lib/observer/src/cdv_wx.erl @@ -197,8 +197,7 @@ setup(#state{frame=Frame, notebook=Notebook}=State) -> MemPanel = add_page(Notebook, ?MEM_STR, cdv_multi_wx, cdv_mem_cb), %% Persistent Terms Panel - PersistentPanel = add_page(Notebook, ?PERSISTENT_STR, - cdv_html_wx, cdv_persistent_cb), + PersistentPanel = add_page(Notebook, ?PERSISTENT_STR, cdv_html_wx, cdv_persistent_cb), %% Memory Panel IntPanel = add_page(Notebook, ?INT_STR, cdv_multi_wx, cdv_int_tab_cb), diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl index 8c3eef5411..c4527ba063 100644 --- a/lib/observer/src/observer_app_wx.erl +++ b/lib/observer/src/observer_app_wx.erl @@ -48,7 +48,7 @@ usegc = false }). --record(paint, {font, pen, brush, sel, links}). +-record(paint, {font, fg, pen, brush, sel, links}). -record(app, {ptree, n2p, links, dim}). -record(box, {x,y, w,h, s1}). @@ -92,7 +92,8 @@ init([Notebook, Parent, _Config]) -> Extra = wxBoxSizer:new(?wxVERTICAL), DrawingArea = wxScrolledWindow:new(P2, [{winid, ?DRAWAREA}, {style,?wxFULL_REPAINT_ON_RESIZE}]), - wxWindow:setBackgroundColour(DrawingArea, ?wxWHITE), + BG = wxWindow:getBackgroundColour(Apps), + wxWindow:setBackgroundStyle(DrawingArea, ?wxBG_STYLE_SYSTEM), wxWindow:setVirtualSize(DrawingArea, 800, 800), wxSplitterWindow:setMinimumPaneSize(Splitter,50), wxSizer:add(Extra, DrawingArea, [{flag, ?wxEXPAND},{proportion, 1}]), @@ -127,7 +128,17 @@ init([Notebook, Parent, _Config]) -> Font0 end, SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), - GreyBrush = wxBrush:new({230,230,240}), + {Fg,BGBrush,Pen} = + case observer_lib:is_darkmode(BG) of + false -> + {wxSystemSettings:getColour(?wxSYS_COLOUR_BTNTEXT), + wxBrush:new(wxSystemSettings:getColour(?wxSYS_COLOUR_BTNSHADOW)), + wxPen:new({80,80,80}, [{width, Scale * 2}])}; + true -> + {wxSystemSettings:getColour(?wxSYS_COLOUR_BTNTEXT), + wxBrush:new(wxSystemSettings:getColour(?wxSYS_COLOUR_BTNSHADOW)), + wxPen:new({0,0,0}, [{width, Scale * 2}])} + end, SelBrush = wxBrush:new(SelCol), LinkPen = wxPen:new(SelCol, [{width, Scale * 2}]), process_flag(trap_exit, true), @@ -137,8 +148,9 @@ init([Notebook, Parent, _Config]) -> app_w =DrawingArea, usegc = UseGC, paint=#paint{font = Font, - pen = wxPen:new({80,80,80}, [{width, Scale * 2}]), - brush= GreyBrush, + fg = Fg, + pen = Pen, + brush= BGBrush, sel = SelBrush, links= LinkPen } @@ -306,11 +318,11 @@ handle_info({delivery, _Pid, app, _Curr, {[], [], [], []}}, handle_info({delivery, Pid, app, Curr, AppData}, State = #state{panel=Panel, appmon=Pid, current=Curr, usegc=UseGC, - app_w=AppWin, paint=#paint{font=Font}}) -> + app_w=AppWin, paint=#paint{fg=Fg, font=Font}}) -> GC = if UseGC -> {?wxGC:create(AppWin), false}; true -> {false, wxWindowDC:new(AppWin)} end, - setFont(GC, Font, {0,0,0}), + setFont(GC, Font, Fg), App = build_tree(AppData, GC), destroy_gc(GC), setup_scrollbar(AppWin, App), @@ -508,13 +520,13 @@ tree_map([], _ , Acc) -> Acc. draw(_DC, undefined, _, _) -> ok; draw(DC, #app{dim={_W,_H}, ptree=Tree, links=Links}, Sel, - #paint{font=Font, pen=Pen, brush=Brush, links=LPen, sel=SelBrush}) -> + #paint{font=Font, fg=Fg, pen=Pen, brush=Brush, links=LPen, sel=SelBrush}) -> setPen(DC, LPen), [draw_xlink(Link, DC) || Link <- Links], setPen(DC, Pen), %% ?wxGC:drawRectangle(DC, 2,2, _W-2,_H-2), %% DEBUG setBrush(DC, Brush), - setFont(DC, Font, {0,0,0}), + setFont(DC, Font, Fg), draw_tree(Tree, root, DC), case Sel of undefined -> ok; diff --git a/lib/observer/src/observer_defs.hrl b/lib/observer/src/observer_defs.hrl index 504d0877d9..7902b32cba 100644 --- a/lib/observer/src/observer_defs.hrl +++ b/lib/observer/src/observer_defs.hrl @@ -36,6 +36,7 @@ check = false }). +-record(colors, {fg, even, odd}). -record(attrs, {even, odd, searched, deleted, changed_odd, changed_even, new_odd, new_even}). -define(EVEN(Row), ((Row rem 2) =:= 0)). -define(BG_EVEN, {230,230,250}). diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl index c67fa28c6d..4c92a8faab 100644 --- a/lib/observer/src/observer_html_lib.erl +++ b/lib/observer/src/observer_html_lib.erl @@ -24,9 +24,9 @@ %% viewer. No logic or states are kept by this module. %% --export([plain_page/1, - expandable_term/3, - warning/1]). +-export([plain_page/2, + expandable_term/4, + warning/2]). -include("crashdump_viewer.hrl"). -include("observer_defs.hrl"). @@ -34,8 +34,9 @@ %%%----------------------------------------------------------------- %%% Display the given information as is, no heading %%% Empty body if no info exists. -warning(Info) -> - header(body(warning_body(Info))). +warning(Info, Colors0) -> + Colors = convert(Colors0), + header(body(warning_body(Info), Colors)). warning_body(Info) -> [warn(Info)]. @@ -43,18 +44,22 @@ warning_body(Info) -> %%%----------------------------------------------------------------- %%% Display the given information as is, no heading %%% Empty body if no info exists. -plain_page(Info) -> - header(body(plain_body(Info))). +plain_page(Info, Colors0) -> + Colors = convert(Colors0), + header(body(plain_body(Info), Colors)). plain_body(Info) -> [pre(href_proc_port(lists:flatten(Info)))]. %%%----------------------------------------------------------------- %%% Expanded memory -expandable_term(Heading,Expanded,Tab) -> - header(Heading,body(expandable_term_body(Heading,Expanded,Tab))). +expandable_term(Heading,Expanded,Tab, Colors0) -> + Colors = convert(Colors0), + header(Heading, + body(expandable_term_body(Heading,Expanded,Tab,Colors), + Colors)). -expandable_term_body(Heading,[],_Tab) -> +expandable_term_body(Heading,[],_Tab, _) -> [case Heading of "MsgQueue" -> "No messages were found"; "Message Queue" -> "No messages were found"; @@ -65,7 +70,7 @@ expandable_term_body(Heading,[],_Tab) -> "SaslLog" -> "No log entry was found"; "Persistent Terms" -> "No persistent terms were found" end]; -expandable_term_body(Heading,Expanded,Tab) -> +expandable_term_body(Heading,Expanded,Tab, Colors) -> Attr = "BORDER=0 CELLPADDING=0 CELLSPACING=1 WIDTH=100%", [case Heading of "MsgQueue" -> @@ -74,7 +79,7 @@ expandable_term_body(Heading,Expanded,Tab) -> [th("WIDTH=70%","Message"), th("WIDTH=30%","SeqTraceToken")]) | element(1, lists:mapfoldl(fun(Msg, Even) -> - {msgq_table(Tab, Msg, Even), + {msgq_table(Tab, Msg, Even, Colors), not Even} end, true, Expanded))]); @@ -84,7 +89,7 @@ expandable_term_body(Heading,Expanded,Tab) -> [th("WIDTH=10%","Id"), th("WIDTH=90%","Message")]) | element(1, lists:mapfoldl(fun(Msg, {Even,N}) -> - {msgq_table(Tab, Msg, N, Even), + {msgq_table(Tab, Msg, N, Even, Colors), {not Even, N+1}} end, {true,1}, Expanded))]); @@ -94,7 +99,7 @@ expandable_term_body(Heading,Expanded,Tab) -> [th("WIDTH=20%","Label"), th("WIDTH=80%","Term")]) | element(1, lists:mapfoldl(fun(Entry, Even) -> - {stackdump_table(Tab, Entry, Even), + {stackdump_table(Tab, Entry, Even, Colors), not Even} end, true, Expanded))]); "ProcState" -> @@ -103,7 +108,7 @@ expandable_term_body(Heading,Expanded,Tab) -> [th("WIDTH=20%","Label"), th("WIDTH=80%","Information")]) | element(1, lists:mapfoldl(fun(Entry, Even) -> - {proc_state(Tab, Entry,Even), + {proc_state(Tab, Entry,Even, Colors), not Even} end, true, Expanded))]); "SaslLog" -> @@ -115,37 +120,37 @@ expandable_term_body(Heading,Expanded,Tab) -> [th("WIDTH=30%","Key"), th("WIDTH=70%","Value")]) | element(1, lists:mapfoldl(fun(Entry, Even) -> - {dict_table(Tab, Entry,Even), + {dict_table(Tab, Entry, Even, Colors), not Even} end, true, Expanded))]) end]. -msgq_table(Tab,{Msg0,Token0}, Even) -> +msgq_table(Tab,{Msg0,Token0}, Even, Colors) -> Token = case Token0 of [] -> ""; _ -> io_lib:fwrite("~w",[Token0]) end, Msg = all_or_expand(Tab,Msg0), - tr(color(Even),[td(pre(Msg)), td(Token)]). + tr(color(Even, Colors),[td(pre(Msg)), td(Token)]). -msgq_table(Tab,Msg0, Id, Even) -> +msgq_table(Tab,Msg0, Id, Even, Colors) -> Msg = all_or_expand(Tab,Msg0), - tr(color(Even),[td(integer_to_list(Id)), td(pre(Msg))]). + tr(color(Even, Colors),[td(integer_to_list(Id)), td(pre(Msg))]). -stackdump_table(Tab,{Label0,Term0},Even) -> +stackdump_table(Tab,{Label0,Term0},Even, Colors) -> Label = io_lib:format("~w",[Label0]), Term = all_or_expand(Tab,Term0), - tr(color(Even), [td("VALIGN=center",pre(Label)), td(pre(Term))]). + tr(color(Even, Colors), [td("VALIGN=center",pre(Label)), td(pre(Term))]). -dict_table(Tab,{Key0,Value0}, Even) -> +dict_table(Tab,{Key0,Value0}, Even, Colors) -> Key = all_or_expand(Tab,Key0), Value = all_or_expand(Tab,Value0), - tr(color(Even), [td("VALIGN=center",pre(Key)), td(pre(Value))]). + tr(color(Even, Colors), [td("VALIGN=center",pre(Key)), td(pre(Value))]). -proc_state(Tab,{Key0,Value0}, Even) -> +proc_state(Tab,{Key0,Value0}, Even, Colors) -> Key = lists:flatten(io_lib:format("~ts",[Key0])), Value = all_or_expand(Tab,Value0), - tr(color(Even), [td("VALIGN=center",Key), td(pre(Value))]). + tr(color(Even, Colors), [td("VALIGN=center",Key), td(pre(Value))]). all_or_expand(Tab,Term) -> Preview = io_lib:format("~tP",[Term,8]), @@ -171,8 +176,8 @@ all_or_expand(Tab,Bin,_PreviewStr,_Expand) Term = io_lib:format("~tp", [OBSBin]), href_proc_port(lists:flatten(Term), true). -color(true) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_EVEN)); -color(false) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_ODD)). +color(true, #colors{even=Even}) -> "BGCOLOR="++Even; +color(false,#colors{odd=Odd}) -> "BGCOLOR="++Odd. %%%----------------------------------------------------------------- %%% Internal library @@ -180,10 +185,10 @@ start_html() -> "<HTML>\n". stop_html() -> "</HTML>". -start_html_body() -> - "<BODY BGCOLOR=\"#FFFFFF\">\n". +start_html_body(#colors{even=Even, fg=Fg}) -> + "<BODY BGCOLOR=" ++ Even ++ ">\n <FONT COLOR=" ++ Fg ++ ">\n". stop_html_body() -> - "</BODY>\n". + "</FONT> </BODY>\n". header(Body) -> header("","",Body). @@ -205,8 +210,8 @@ only_html_header(Title,JavaScript) -> JavaScript, "</HEAD>\n"]. -body(Text) -> - [start_html_body(), +body(Text, Colors) -> + [start_html_body(Colors), Text, stop_html_body()]. @@ -417,3 +422,8 @@ warn([]) -> []; warn(Warning) -> font("COLOR=\"#FF0000\"",p([Warning,br(),br()])). + +convert(#colors{fg={FR,FB,FG}, even={ER,EB,EG}, odd={OR,OG,OB}}) -> + #colors{fg = io_lib:format("\"#~2.16.0B~2.16.0B~2.16.0B\"", [FR,FB,FG]), + even = io_lib:format("\"#~2.16.0B~2.16.0B~2.16.0B\"", [ER,EB,EG]), + odd = io_lib:format("\"#~2.16.0B~2.16.0B~2.16.0B\"", [OR,OG,OB])}. diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index 7c68b0ebb6..7d115306bd 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -28,8 +28,8 @@ interval_dialog/4, start_timer/1, start_timer/2, stop_timer/1, timer_config/1, display_info/2, display_info/3, fill_info/2, update_info/2, to_str/1, create_menus/3, create_menu_item/3, - create_attrs/0, - set_listctrl_col_size/2, + is_darkmode/1, colors/1, create_attrs/1, + set_listctrl_col_size/2, mix/3, create_status_bar/1, html_window/1, html_window/2, make_obsbin/2, @@ -373,26 +373,44 @@ create_menu_item(separator, Menu, Index) -> wxMenu:insertSeparator(Menu, Index), Index+1. -create_attrs() -> - Font = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), +colors(Window) -> + DarkMode = is_darkmode(wxWindow:getBackgroundColour(Window)), Text = case wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOXTEXT) of - {255,255,255,_} -> {10,10,10}; %% Is white on Mac for some reason - Color -> Color - end, - #attrs{even = wxListItemAttr:new(Text, ?BG_EVEN, Font), - odd = wxListItemAttr:new(Text, ?BG_ODD, Font), - deleted = wxListItemAttr:new(?FG_DELETED, ?BG_DELETED, Font), - changed_even = wxListItemAttr:new(Text, mix(?BG_CHANGED,?BG_EVEN), Font), - changed_odd = wxListItemAttr:new(Text, mix(?BG_CHANGED,?BG_ODD), Font), - new_even = wxListItemAttr:new(Text, mix(?BG_NEW,?BG_EVEN), Font), - new_odd = wxListItemAttr:new(Text, mix(?BG_NEW, ?BG_ODD), Font), - searched = wxListItemAttr:new(Text, ?BG_SEARCHED, Font) - }. - -mix(RGB,_) -> RGB. - -%% mix({R,G,B},{MR,MG,MB}) -> -%% {trunc(R*MR/255), trunc(G*MG/255), trunc(B*MB/255)}. + {255,255,255,_} when not DarkMode -> {10,10,10}; %% Is white on Mac for some reason + Color -> Color + end, + Even = wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOX), + Odd = mix(Even, wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), 0.8), + #colors{fg=rgb(Text), even=rgb(Even), odd=rgb(Odd)}. + +create_attrs(Window) -> + Font = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + #colors{fg=Text, even=Even, odd=Odd} = colors(Window), + #attrs{even = wxListItemAttr:new(Text, Even, Font), + odd = wxListItemAttr:new(Text, Odd, Font), + deleted = wxListItemAttr:new(?FG_DELETED, ?BG_DELETED, Font), + changed_even = wxListItemAttr:new(Text, mix(?BG_CHANGED, ?BG_EVEN, 0.9), Font), + changed_odd = wxListItemAttr:new(Text, mix(?BG_CHANGED, ?BG_ODD, 0.9), Font), + new_even = wxListItemAttr:new(Text, mix(?BG_NEW, ?BG_EVEN, 0.9), Font), + new_odd = wxListItemAttr:new(Text, mix(?BG_NEW, ?BG_ODD, 0.9), Font), + searched = wxListItemAttr:new(Text, ?BG_SEARCHED, Font) + }. + +rgb({R,G,B,_}) -> {R,G,B}; +rgb({_,_,_}=RGB) -> RGB. + +mix(RGB,{MR,MG,MB,_}, V) -> + mix(RGB, {MR,MG,MB}, V); +mix({R,G,B,_}, RGB, V) -> + mix({R,G,B}, RGB, V); +mix({R,G,B},{MR,MG,MB}, V) when V =< 1.0 -> + {min(255, round(R*V+MR*(1.0-V))), + min(255, round(G*V+MG*(1.0-V))), + min(255, round(B*V+MB*(1.0-V)))}. + + +is_darkmode({R,G,B,_}) -> + ((R+G+B) div 3) < 100. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 79271addf2..50a6d6a915 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -55,7 +55,7 @@ -define(wxGC, wxGraphicsContext). --record(paint, {font, small, pen, pen2, pens, dot_pens, usegc = false}). +-record(paint, {font, small, fg, pen, pen2, pens, dot_pens, usegc = false}). start_link(Notebook, Parent, Config) -> wx_object:start_link(?MODULE, [Notebook, Parent, Config], []). @@ -126,7 +126,16 @@ setup_graph_drawing(Panels) -> SF = wxFont:new(Scale * (DefSize-2), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), {F, SF} end, - BlackPen = wxPen:new({0,0,0}, [{width, Scale}]), + BG = wxWindow:getBackgroundColour((hd(Panels))#win.panel), + Fg = case observer_lib:is_darkmode(BG) of + false -> {0,0,0}; + true -> wxSystemSettings:getColour(?wxSYS_COLOUR_BTNTEXT) + end, + + PenColor = case observer_lib:is_darkmode(BG) of + false -> {0,0,0}; + true -> {0,0,0} + end, Pens = [wxPen:new(Col, [{width, Scale}, {style, ?wxSOLID}]) || Col <- tuple_to_list(colors())], DotPens = [wxPen:new(Col, [{width, Scale}, {style, ?wxDOT}]) @@ -134,8 +143,9 @@ setup_graph_drawing(Panels) -> #paint{usegc = UseGC, font = Font, small = SmallFont, - pen = ?wxGREY_PEN, - pen2 = BlackPen, + fg = Fg, %% Text color + pen = wxPen:new(PenColor), + pen2 = wxPen:new(PenColor, [{width, Scale}]), pens = list_to_tuple(Pens), dot_pens = list_to_tuple(DotPens) }. @@ -525,7 +535,7 @@ draw_win(DC, #win{name=Name, no_samples=Samples, geom=#{scale:={WS,HS}}, DrawBs(), ok; -draw_win(DC, #win{no_samples=Samples} = Win,Ti, #paint{small=Small}=Paint) -> +draw_win(DC, #win{no_samples=Samples} = Win,Ti, #paint{fg=Fg, small=Small}=Paint) -> %% Draw Error Msg try draw_borders(DC, Ti, Win, Paint) of {X0,_Y0,DrawBs} -> @@ -533,7 +543,7 @@ draw_win(DC, #win{no_samples=Samples} = Win,Ti, #paint{small=Small}=Paint) -> true -> "Waiting for data"; false -> "Information not available" end, - setFont(DC, Small, {0,0,0}), + setFont(DC, Small, Fg), {_,WW} = getSize(DC), drawText(DC, Text, X0 + 100, WW div 2), DrawBs(), @@ -628,7 +638,7 @@ spline_tan(Y0, Y1, Y2, Y3) -> draw_borders(DC, #ti{secs=Secs, fetch=FetchFreq}, #win{name=Type, geom=Geom, info=Info, max={_,_,Unit,_}}, - #paint{pen=Pen, pen2=Pen2, font=Font, small=Small}) -> + #paint{pen=Pen, pen2=Pen2, fg=Fg, font=Font, small=Small}) -> #{p0:={GraphX0, GraphY0}, p1:={GraphX1,GraphY1}, scale:={ScaleW0,_}, txsz:={TW,TH,SpaceW}, txt:={BottomTextY, MaxTextY}, strs:={Str1,Str2,Str3}} = Geom, @@ -640,7 +650,7 @@ draw_borders(DC, #ti{secs=Secs, fetch=FetchFreq}, GraphY50 = GraphY0 + (GraphY1 - GraphY0) / 2, GraphY75 = GraphY0 + 3*(GraphY1 - GraphY0) / 4, - setFont(DC, Small, {0,0,0}), + setFont(DC, Small, Fg), Align = fun(Str, Y) -> {StrW, _} = getTextExtent(DC, Str), drawText(DC, Str, GraphX0 - StrW - ?BW, Y) @@ -670,11 +680,11 @@ draw_borders(DC, #ti{secs=Secs, fetch=FetchFreq}, strokeLine(DC, GraphX0-3, GraphY50, GraphX1, GraphY50), strokeLine(DC, GraphX0-3, GraphY75, GraphX1, GraphY75), - setFont(DC, Font, {0,0,0}), + setFont(DC, Font, Fg), Text = fun(X,Y, Str, PenId) -> if PenId == 0 -> - setFont(DC, Font, {0,0,0}); + setFont(DC, Font, Fg); PenId > 0 -> Id = 1 + ((PenId-1) rem tuple_size(colors())), setFont(DC, Font, element(Id, colors())) diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl index 00cf1b5fba..5cb6d9bc22 100644 --- a/lib/observer/src/observer_port_wx.erl +++ b/lib/observer/src/observer_port_wx.erl @@ -61,7 +61,8 @@ inet}). -record(opt, {sort_key=2, - sort_incr=true + sort_incr=true, + odd_bg }). -record(state, @@ -111,7 +112,10 @@ init([Notebook, Parent, Config]) -> wxListCtrl:connect(Grid, size, [{skip, true}]), wxWindow:setFocus(Grid), - {Panel, #state{grid=Grid, parent=Parent, panel=Panel, timer=Config}}. + Even = wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOX), + Odd = observer_lib:mix(Even, wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), 0.8), + Opt = #opt{odd_bg=Odd}, + {Panel, #state{grid=Grid, parent=Parent, panel=Panel, timer=Config, opt=Opt}}. handle_event(#wx{id=?ID_REFRESH}, State = #state{node=Node, grid=Grid, opt=Opt}) -> @@ -553,7 +557,7 @@ filter_monitor_info() -> update_grid(Grid, Sel, Opt, Ports) -> wx:batch(fun() -> update_grid2(Grid, Sel, Opt, Ports) end). -update_grid2(Grid, Sel, #opt{sort_key=Sort,sort_incr=Dir}, Ports) -> +update_grid2(Grid, Sel, #opt{sort_key=Sort,sort_incr=Dir, odd_bg=BG}, Ports) -> wxListCtrl:deleteAllItems(Grid), Update = fun(#port{id = Id, @@ -563,8 +567,8 @@ update_grid2(Grid, Sel, #opt{sort_key=Sort,sort_incr=Dir}, Ports) -> controls = Ctrl}, Row) -> _Item = wxListCtrl:insertItem(Grid, Row, ""), - if (Row rem 2) =:= 0 -> - wxListCtrl:setItemBackgroundColour(Grid, Row, ?BG_EVEN); + if (Row rem 2) =:= 1 -> + wxListCtrl:setItemBackgroundColour(Grid, Row, BG); true -> ignore end, diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl index 4ab4a78462..6b359f3c44 100644 --- a/lib/observer/src/observer_pro_wx.erl +++ b/lib/observer/src/observer_pro_wx.erl @@ -94,7 +94,7 @@ start_link(Notebook, Parent, Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init([Notebook, Parent, Config]) -> - Attrs = observer_lib:create_attrs(), + Attrs = observer_lib:create_attrs(Notebook), Self = self(), Acc = maps:get(acc, Config, false), Holder = spawn_link(fun() -> init_table_holder(Self, Acc, Attrs) end), diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index bd5fed0951..637a090a15 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -214,12 +214,14 @@ init_process_page(Panel, Pid) -> init_message_page(Parent, Pid, Table) -> Win = observer_lib:html_window(Parent), + Cs = observer_lib:colors(Parent), Update = fun() -> case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]) of {messages, Messages} -> - Html = observer_html_lib:expandable_term("Message Queue", Messages, Table), + Html = observer_html_lib:expandable_term("Message Queue", Messages, + Table, Cs), wxHtmlWindow:setPage(Win, Html); _ -> throw(process_undefined) @@ -230,11 +232,12 @@ init_message_page(Parent, Pid, Table) -> init_dict_page(Parent, Pid, Table) -> Win = observer_lib:html_window(Parent), + Cs = observer_lib:colors(Parent), Update = fun() -> case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]) of {dictionary,Dict} -> - Html = observer_html_lib:expandable_term("Dictionary", Dict, Table), + Html = observer_html_lib:expandable_term("Dictionary", Dict, Table, Cs), wxHtmlWindow:setPage(Win, Html); _ -> throw(process_undefined) @@ -254,6 +257,8 @@ init_stack_page(Parent, Pid) -> wxListCtrl:insertColumn(LCtrl, 1, Li), wxListCtrl:setColumnWidth(LCtrl, 1, Scale * 300), wxListItem:destroy(Li), + Even = wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOX), + Odd = observer_lib:mix(Even, wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), 0.8), Update = fun() -> case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, current_stacktrace]) @@ -262,8 +267,8 @@ init_stack_page(Parent, Pid) -> wxListCtrl:deleteAllItems(LCtrl), wx:foldl(fun({M, F, A, Info}, Row) -> _Item = wxListCtrl:insertItem(LCtrl, Row, ""), - ?EVEN(Row) andalso - wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + ?EVEN(Row) orelse + wxListCtrl:setItemBackgroundColour(LCtrl, Row, Odd), wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})), FileLine = case Info of [{file,File},{line,Line}] -> @@ -288,9 +293,10 @@ init_stack_page(Parent, Pid) -> init_state_page(Parent, Pid, Table) -> Win = observer_lib:html_window(Parent), + Cs = observer_lib:colors(Parent), Update = fun() -> StateInfo = fetch_state_info(Pid), - Html = observer_html_lib:expandable_term("ProcState", StateInfo, Table), + Html = observer_html_lib:expandable_term("ProcState", StateInfo, Table, Cs), wxHtmlWindow:setPage(Win, Html) end, Update(), @@ -341,6 +347,7 @@ fetch_state_info2(Pid, M) -> init_log_page(Parent, Pid, Table) -> Win = observer_lib:html_window(Parent), + Cs = observer_lib:colors(Parent), Update = fun() -> Fd = spawn_link(fun() -> io_server() end), rpc:call(node(Pid), rb, rescan, [[{start_log, Fd}]]), @@ -353,7 +360,7 @@ init_log_page(Parent, Pid, Table) -> NbBlanks = length(Pref) - 1, Re = "(<" ++ Pref ++ "\.[^>]{1,}>)[ ]{"++ integer_to_list(NbBlanks) ++ "}", Look = re:replace(ExpPid, Re, "\\1", [global, {return, list}]), - Html = observer_html_lib:expandable_term("SaslLog", Look, Table), + Html = observer_html_lib:expandable_term("SaslLog", Look, Table, Cs), wxHtmlWindow:setPage(Win, Html) end, Update(), diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index 7bd67a0f0b..32d75f77d4 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -116,8 +116,8 @@ init([Parent, Opts]) -> TabId = table_id(Table), ColumnNames = column_names(Node, Source, TabId), KeyPos = key_pos(Node, Source, TabId), - - Attrs = observer_lib:create_attrs(), + Panel = wxPanel:new(Frame), + Attrs = observer_lib:create_attrs(Panel), Self = self(), Holder = spawn_link(fun() -> @@ -125,7 +125,6 @@ init([Parent, Opts]) -> length(ColumnNames), Node, Attrs) end), - Panel = wxPanel:new(Frame), Sizer = wxBoxSizer:new(?wxVERTICAL), Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, Grid = wxListCtrl:new(Panel, [{style, Style}, diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl index 9743a6ed42..d622b1423b 100644 --- a/lib/observer/src/observer_tv_wx.erl +++ b/lib/observer/src/observer_tv_wx.erl @@ -71,7 +71,7 @@ init([Notebook, Parent, Config]) -> Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES, Self = self(), - Attrs = observer_lib:create_attrs(), + Attrs = observer_lib:create_attrs(Panel), Holder = spawn_link(fun() -> init_table_holder(Self, Attrs) end), CBs = [{onGetItemText, fun(_, Item,Col) -> get_row(Holder, Item, Col) end}, {onGetItemAttr, fun(_, Item) -> get_attr(Holder, Item) end}], |