diff options
Diffstat (limited to 'erts/preloaded/src')
-rw-r--r-- | erts/preloaded/src/Makefile | 2 | ||||
-rw-r--r-- | erts/preloaded/src/add_abstract_code | 16 | ||||
-rw-r--r-- | erts/preloaded/src/erlang.erl | 141 | ||||
-rw-r--r-- | erts/preloaded/src/erts_code_purger.erl | 340 | ||||
-rw-r--r-- | erts/preloaded/src/erts_dirty_process_code_checker.erl | 3 | ||||
-rw-r--r-- | erts/preloaded/src/erts_internal.erl | 66 | ||||
-rw-r--r-- | erts/preloaded/src/init.erl | 59 | ||||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 5 | ||||
-rw-r--r-- | erts/preloaded/src/zlib.erl | 41 |
9 files changed, 347 insertions, 326 deletions
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 2ab9edaf5e..edb9f35258 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -73,7 +73,7 @@ KERNEL_SRC=$(ERL_TOP)/lib/kernel/src KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include -ERL_COMPILE_FLAGS += +warn_obsolete_guard +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) +ERL_COMPILE_FLAGS += +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) debug opt: $(TARGET_FILES) diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index 943987872e..9040199417 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% Copyright Ericsson AB 2013-2017. 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. @@ -28,12 +28,12 @@ main([BeamFile,AbstrFile]) -> {ok,_,Chunks0} = beam_lib:all_chunks(BeamFile), {ok,Abstr} = file:consult(AbstrFile), - Chunks1 = lists:keyreplace("Abst", 1, Chunks0, - {"Abst",term_to_binary({raw_abstract_v1,Abstr})}), - {"CInf",CInf0} = lists:keyfind("CInf", 1, Chunks1), - CInf = fix_options(CInf0), - Chunks = lists:keyreplace("CInf", 1, Chunks1, {"CInf",CInf}), - {ok,Module} = beam_lib:build_module(Chunks), + {"CInf",CInf0} = lists:keyfind("CInf", 1, Chunks0), + {CInf, COpts} = fix_options(CInf0), + Chunks1 = lists:keyreplace("CInf", 1, Chunks0, {"CInf",CInf}), + Chunks2 = lists:keyreplace("Dbgi", 1, Chunks1, + {"Dbgi",term_to_binary({debug_info_v1,erl_abstract_code,{Abstr, COpts}})}), + {ok,Module} = beam_lib:build_module(Chunks2), ok = file:write_file(BeamFile, Module), init:stop(). @@ -42,4 +42,4 @@ fix_options(CInf0) -> {options,Opts0} = lists:keyfind(options, 1, CInf1), Opts = Opts0 -- [from_asm], CInf = lists:keyreplace(options, 1, CInf1, {options,Opts}), - term_to_binary(CInf). + {term_to_binary(CInf), Opts}. diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 8771089b65..72dd804412 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -48,7 +48,7 @@ await_sched_wall_time_modifications/2, gather_gc_info_result/1]). --deprecated([hash/2, now/0]). +-deprecated([now/0]). %% Get rid of autoimports of spawn to avoid clashes with ourselves. -compile({no_auto_import,[spawn_link/1]}). @@ -83,6 +83,10 @@ | 'micro_seconds' | 'nano_seconds'. +-opaque prepared_code() :: reference(). + +-export_type([prepared_code/0]). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Native code BIF stubs and their types %% (BIF's actually implemented in this module goes last in the file) @@ -100,7 +104,8 @@ -export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). -export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). --export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2, +-export([cancel_timer/1, cancel_timer/2, ceil/1, + check_old_code/1, check_process_code/2, check_process_code/3, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). @@ -109,13 +114,13 @@ -export([error/1, error/2, exit/1, exit/2, external_size/1]). -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_binary/1, float_to_binary/2, - float_to_list/1, float_to_list/2]). + float_to_list/1, float_to_list/2, floor/1]). -export([fun_info/2, fun_info_mfa/1, fun_to_list/1, function_exported/3]). -export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/0, get_keys/1]). -export([get_module_info/1, get_stacktrace/0, group_leader/0]). -export([group_leader/2]). --export([halt/0, halt/1, halt/2, hash/2, +-export([halt/0, halt/1, halt/2, has_prepared_code_on_load/1, hibernate/3]). -export([insert_element/3]). -export([integer_to_binary/1, integer_to_list/1]). @@ -124,7 +129,7 @@ -export([list_to_atom/1, list_to_binary/1]). -export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). -export([list_to_integer/1, list_to_integer/2]). --export([list_to_pid/1, list_to_tuple/1, loaded/0]). +-export([list_to_pid/1, list_to_port/1, list_to_ref/1, list_to_tuple/1, loaded/0]). -export([localtime/0, make_ref/0]). -export([map_size/1, match_spec_test/3, md5/1, md5_final/1]). -export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]). @@ -474,6 +479,13 @@ cancel_timer(_TimerRef) -> cancel_timer(_TimerRef, _Options) -> erlang:nif_error(undefined). +%% ceil/1 +%% Shadowed by erl_bif_types: erlang:ceil/1 +-spec ceil(Number) -> integer() when + Number :: number(). +ceil(_) -> + erlang:nif_error(undef). + %% check_old_code/1 -spec check_old_code(Module) -> boolean() when Module :: module(). @@ -783,9 +795,9 @@ external_size(_Term, _Options) -> erlang:nif_error(undefined). %% finish_loading/2 --spec erlang:finish_loading(PreparedCodeBinaries) -> ok | Error when - PreparedCodeBinaries :: [PreparedCodeBinary], - PreparedCodeBinary :: binary(), +-spec erlang:finish_loading(PreparedCodeList) -> ok | Error when + PreparedCodeList :: [PreparedCode], + PreparedCode :: prepared_code(), ModuleList :: [module()], Error :: {not_purged,ModuleList} | {on_load,ModuleList}. finish_loading(_List) -> @@ -837,6 +849,13 @@ float_to_list(_Float) -> float_to_list(_Float, _Options) -> erlang:nif_error(undefined). +%% floor/1 +%% Shadowed by erl_bif_types: erlang:floor/1 +-spec floor(Number) -> integer() when + Number :: number(). +floor(_) -> + erlang:nif_error(undef). + %% fun_info/2 -spec erlang:fun_info(Fun, Item) -> {Item, Info} when Fun :: function(), @@ -871,7 +890,7 @@ function_exported(_Module, _Function, _Arity) -> %% garbage_collect/0 -spec garbage_collect() -> true. garbage_collect() -> - erlang:nif_error(undefined). + erts_internal:garbage_collect(major). %% garbage_collect/1 -spec garbage_collect(Pid) -> GCResult when @@ -884,36 +903,39 @@ garbage_collect(Pid) -> error:Error -> erlang:error(Error, [Pid]) end. +-record(gcopt, { + async = sync :: sync | {async, _}, + type = major % default major, can also be minor + }). + %% garbage_collect/2 -spec garbage_collect(Pid, OptionList) -> GCResult | async when Pid :: pid(), RequestId :: term(), - Option :: {async, RequestId}, + Option :: {async, RequestId} | {type, 'major' | 'minor'}, OptionList :: [Option], GCResult :: boolean(). garbage_collect(Pid, OptionList) -> try - Async = get_gc_opts(OptionList, sync), - case Async of + GcOpts = get_gc_opts(OptionList, #gcopt{}), + case GcOpts#gcopt.async of {async, ReqId} -> {priority, Prio} = erlang:process_info(erlang:self(), priority), - erts_internal:request_system_task(Pid, - Prio, - {garbage_collect, ReqId}), + erts_internal:request_system_task( + Pid, Prio, {garbage_collect, ReqId, GcOpts#gcopt.type}), async; sync -> case Pid == erlang:self() of true -> - erlang:garbage_collect(); + erts_internal:garbage_collect(GcOpts#gcopt.type); false -> {priority, Prio} = erlang:process_info(erlang:self(), priority), ReqId = erlang:make_ref(), - erts_internal:request_system_task(Pid, - Prio, - {garbage_collect, - ReqId}), + erts_internal:request_system_task( + Pid, Prio, + {garbage_collect, ReqId, GcOpts#gcopt.type}), receive {garbage_collect, ReqId, GCResult} -> GCResult @@ -925,10 +947,12 @@ garbage_collect(Pid, OptionList) -> end. % gets async opt and verify valid option list -get_gc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync) -> - get_gc_opts(Options, AsyncTuple); -get_gc_opts([], Async) -> - Async. +get_gc_opts([{async, _ReqId} = AsyncTuple | Options], GcOpt = #gcopt{}) -> + get_gc_opts(Options, GcOpt#gcopt{ async = AsyncTuple }); +get_gc_opts([{type, T} | Options], GcOpt = #gcopt{}) -> + get_gc_opts(Options, GcOpt#gcopt{ type = T }); +get_gc_opts([], GcOpt) -> + GcOpt. %% garbage_collect_message_area/0 -spec erlang:garbage_collect_message_area() -> boolean(). @@ -963,9 +987,10 @@ get_keys(_Val) -> erlang:nif_error(undefined). %% get_module_info/1 --spec erlang:get_module_info(P1) -> [{atom(), [{atom(), term()}]}] when - P1 :: atom(). -get_module_info(_P1) -> +-spec erlang:get_module_info(Module) -> [{Item, term()}] when + Item :: module | exports | attributes | compile | native | md5, + Module :: atom(). +get_module_info(_Module) -> erlang:nif_error(undefined). %% get_stacktrace/0 @@ -1007,16 +1032,9 @@ halt(Status) -> halt(_Status, _Options) -> erlang:nif_error(undefined). -%% hash/2 --spec erlang:hash(Term, Range) -> pos_integer() when - Term :: term(), - Range :: pos_integer(). -hash(_Term, _Range) -> - erlang:nif_error(undefined). - %% has_prepared_code_on_load/1 -spec erlang:has_prepared_code_on_load(PreparedCode) -> boolean() when - PreparedCode :: binary(). + PreparedCode :: prepared_code(). has_prepared_code_on_load(_PreparedCode) -> erlang:nif_error(undefined). @@ -1142,6 +1160,18 @@ list_to_integer(_String,_Base) -> list_to_pid(_String) -> erlang:nif_error(undefined). +%% list_to_port/1 +-spec list_to_port(String) -> port() when + String :: string(). +list_to_port(_String) -> + erlang:nif_error(undefined). + +%% list_to_ref/1 +-spec list_to_ref(String) -> reference() when + String :: string(). +list_to_ref(_String) -> + erlang:nif_error(undefined). + %% list_to_tuple/1 -spec list_to_tuple(List) -> tuple() when List :: [term()]. @@ -1313,7 +1343,7 @@ pid_to_list(_Pid) -> erlang:nif_error(undefined). %% port_to_list/1 --spec erlang:port_to_list(Port) -> string() when +-spec port_to_list(Port) -> string() when Port :: port(). port_to_list(_Port) -> erlang:nif_error(undefined). @@ -1433,7 +1463,7 @@ timestamp() -> -spec erlang:prepare_loading(Module, Code) -> PreparedCode | {error, Reason} when Module :: module(), Code :: binary(), - PreparedCode :: binary(), + PreparedCode :: prepared_code(), Reason :: bad_file. prepare_loading(_Module, _Code) -> erlang:nif_error(undefined). @@ -1523,7 +1553,7 @@ read_timer(_TimerRef, _Options) -> erlang:nif_error(undefined). %% ref_to_list/1 --spec erlang:ref_to_list(Ref) -> string() when +-spec ref_to_list(Ref) -> string() when Ref :: reference(). ref_to_list(_Ref) -> erlang:nif_error(undefined). @@ -1862,10 +1892,12 @@ element(_N, _Tuple) -> erlang:nif_error(undefined). %% Not documented +-type module_info_key() :: attributes | compile | exports | functions | md5 + | module | native | native_addresses. -spec erlang:get_module_info(Module, Item) -> ModuleInfo when Module :: atom(), - Item :: module | exports | functions | attributes | compile | native_addresses | md5, - ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. + Item :: module_info_key(), + ModuleInfo :: term(). get_module_info(_Module, _Item) -> erlang:nif_error(undefined). @@ -1991,8 +2023,8 @@ load_module(Mod, Code) -> case erlang:prepare_loading(Mod, Code) of {error,_}=Error -> Error; - Bin when erlang:is_binary(Bin) -> - case erlang:finish_loading([Bin]) of + Prep when erlang:is_reference(Prep) -> + case erlang:finish_loading([Prep]) of ok -> {module,Mod}; {Error,[Mod]} -> @@ -2274,6 +2306,8 @@ spawn_opt(_Tuple) -> -spec statistics(active_tasks) -> [ActiveTasks] when ActiveTasks :: non_neg_integer(); + (active_tasks_all) -> [ActiveTasks] when + ActiveTasks :: non_neg_integer(); (context_switches) -> {ContextSwitches,0} when ContextSwitches :: non_neg_integer(); (exact_reductions) -> {Total_Exact_Reductions, @@ -2301,8 +2335,10 @@ spawn_opt(_Tuple) -> Total_Reductions :: non_neg_integer(), Reductions_Since_Last_Call :: non_neg_integer(); (run_queue) -> non_neg_integer(); - (run_queue_lengths) -> [RunQueueLenght] when - RunQueueLenght :: non_neg_integer(); + (run_queue_lengths) -> [RunQueueLength] when + RunQueueLength :: non_neg_integer(); + (run_queue_lengths_all) -> [RunQueueLength] when + RunQueueLength :: non_neg_integer(); (runtime) -> {Total_Run_Time, Time_Since_Last_Call} when Total_Run_Time :: non_neg_integer(), Time_Since_Last_Call :: non_neg_integer(); @@ -2310,10 +2346,18 @@ spawn_opt(_Tuple) -> SchedulerId :: pos_integer(), ActiveTime :: non_neg_integer(), TotalTime :: non_neg_integer(); + (scheduler_wall_time_all) -> [{SchedulerId, ActiveTime, TotalTime}] | undefined when + SchedulerId :: pos_integer(), + ActiveTime :: non_neg_integer(), + TotalTime :: non_neg_integer(); (total_active_tasks) -> ActiveTasks when + ActiveTasks :: non_neg_integer(); + (total_active_tasks_all) -> ActiveTasks when ActiveTasks :: non_neg_integer(); - (total_run_queue_lengths) -> TotalRunQueueLenghts when - TotalRunQueueLenghts :: non_neg_integer(); + (total_run_queue_lengths) -> TotalRunQueueLengths when + TotalRunQueueLengths :: non_neg_integer(); + (total_run_queue_lengths_all) -> TotalRunQueueLengths when + TotalRunQueueLengths :: non_neg_integer(); (wall_clock) -> {Total_Wallclock_Time, Wallclock_Time_Since_Last_Call} when Total_Wallclock_Time :: non_neg_integer(), @@ -2509,6 +2553,8 @@ tuple_to_list(_Tuple) -> Alloc :: atom(); ({allocator_sizes, Alloc}) -> [_] when %% More or less anything Alloc :: atom(); + (atom_count) -> pos_integer(); + (atom_limit) -> pos_integer(); (build_type) -> opt | debug | purify | quantify | purecov | gcov | valgrind | gprof | lcnt | frmptr; (c_compiler_used) -> {atom(), term()}; @@ -3989,6 +4035,7 @@ sched_wall_time(Ref, N, undefined) -> sched_wall_time(Ref, N, Acc) -> receive {Ref, undefined} -> sched_wall_time(Ref, N-1, undefined); + {Ref, SWTL} when erlang:is_list(SWTL) -> sched_wall_time(Ref, N-1, Acc ++ SWTL); {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc]) end. diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 28d71fd07e..fd214228c7 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -29,29 +29,34 @@ start() -> register(erts_code_purger, self()), process_flag(trap_exit, true), - loop(). - -loop() -> - _ = receive - {purge,Mod,From,Ref} when is_atom(Mod), is_pid(From) -> - Res = do_purge(Mod), - From ! {reply, purge, Res, Ref}; - - {soft_purge,Mod,From,Ref} when is_atom(Mod), is_pid(From) -> - Res = do_soft_purge(Mod), - From ! {reply, soft_purge, Res, Ref}; - - {finish_after_on_load,{Mod,Keep},From,Ref} - when is_atom(Mod), is_pid(From) -> - Res = do_finish_after_on_load(Mod, Keep), - From ! {reply, finish_after_on_load, Res, Ref}; - - {test_purge, Mod, From, Type, Ref} when is_atom(Mod), is_pid(From) -> - do_test_purge(Mod, From, Type, Ref); - - _Other -> ignore - end, - loop(). + wait_for_request(). + +wait_for_request() -> + handle_request(receive Msg -> Msg end, []). + +handle_request({purge, Mod, From, Ref}, Reqs) when is_atom(Mod), is_pid(From) -> + {Res, NewReqs} = do_purge(Mod, Reqs), + From ! {reply, purge, Res, Ref}, + check_requests(NewReqs); +handle_request({soft_purge, Mod, From, Ref}, Reqs) when is_atom(Mod), is_pid(From) -> + {Res, NewReqs} = do_soft_purge(Mod, Reqs), + From ! {reply, soft_purge, Res, Ref}, + check_requests(NewReqs); +handle_request({finish_after_on_load, {Mod,Keep}, From, Ref}, Reqs) + when is_atom(Mod), is_boolean(Keep), is_pid(From) -> + NewReqs = do_finish_after_on_load(Mod, Keep, Reqs), + From ! {reply, finish_after_on_load, ok, Ref}, + check_requests(NewReqs); +handle_request({test_purge, Mod, From, Type, Ref}, Reqs) when is_atom(Mod), is_pid(From) -> + NewReqs = do_test_purge(Mod, From, Type, Ref, Reqs), + check_requests(NewReqs); +handle_request(_Garbage, Reqs) -> + check_requests(Reqs). + +check_requests([]) -> + wait_for_request(); +check_requests([R|Rs]) -> + handle_request(R, Rs). %% %% Processes that tries to call a fun that belongs to @@ -99,14 +104,15 @@ purge(Mod) when is_atom(Mod) -> Result end. -do_purge(Mod) -> +do_purge(Mod, Reqs) -> case erts_internal:purge_module(Mod, prepare) of false -> - {false, false}; + {{false, false}, Reqs}; true -> - DidKill = check_proc_code(erlang:processes(), Mod, true), + {DidKill, NewReqs} = check_proc_code(erlang:processes(), + Mod, true, Reqs), true = erts_internal:purge_module(Mod, complete), - {true, DidKill} + {{true, DidKill}, NewReqs} end. %% soft_purge(Module) @@ -122,17 +128,14 @@ soft_purge(Mod) -> Result end. -do_soft_purge(Mod) -> +do_soft_purge(Mod, Reqs) -> case erts_internal:purge_module(Mod, prepare) of false -> - true; + {true, Reqs}; true -> - Res = check_proc_code(erlang:processes(), Mod, false), - erts_internal:purge_module(Mod, - case Res of - false -> abort; - true -> complete - end) + {PurgeOp, NewReqs} = check_proc_code(erlang:processes(), + Mod, false, Reqs), + {erts_internal:purge_module(Mod, PurgeOp), NewReqs} end. %% finish_after_on_load(Module, Keep) @@ -147,179 +150,130 @@ finish_after_on_load(Mod, Keep) -> Result end. -do_finish_after_on_load(Mod, Keep) -> +do_finish_after_on_load(Mod, Keep, Reqs) -> erlang:finish_after_on_load(Mod, Keep), case Keep of true -> - ok; + Reqs; false -> case erts_internal:purge_module(Mod, prepare_on_load) of false -> - true; + Reqs; true -> - _ = check_proc_code(erlang:processes(), Mod, true), - true = erts_internal:purge_module(Mod, complete) + {_DidKill, NewReqs} = + check_proc_code(erlang:processes(), + Mod, true, Reqs), + true = erts_internal:purge_module(Mod, complete), + NewReqs end end. - %% -%% check_proc_code(Pids, Mod, Hard) - Send asynchronous +%% check_proc_code(Pids, Mod, Hard, Preqs) - Send asynchronous %% requests to all processes to perform a check_process_code %% operation. Each process will check their own state and %% reply with the result. If 'Hard' equals %% - true, processes that refer 'Mod' will be killed. If %% any processes were killed true is returned; otherwise, %% false. -%% - false, and any processes refer 'Mod', false will -%% returned; otherwise, true. +%% - false, and any processes refer 'Mod', 'abort' will +%% be returned; otherwise, 'complete'. %% -%% Requests will be sent to all processes identified by -%% Pids at once, but without allowing GC to be performed. -%% Check process code operations that are aborted due to -%% GC need, will be restarted allowing GC. However, only -%% ?MAX_CPC_GC_PROCS outstanding operation allowing GC at -%% a time will be allowed. This in order not to blow up -%% memory wise. -%% -%% We also only allow ?MAX_CPC_NO_OUTSTANDING_KILLS +%% We only allow ?MAX_CPC_NO_OUTSTANDING_KILLS %% outstanding kills. This both in order to avoid flooding %% our message queue with 'DOWN' messages and limiting the %% amount of memory used to keep references to all %% outstanding kills. %% -%% We maybe should allow more than two outstanding -%% GC requests, but for now we play it safe... --define(MAX_CPC_GC_PROCS, 2). -define(MAX_CPC_NO_OUTSTANDING_KILLS, 10). --record(cpc_static, {hard, module, tag}). +-record(cpc_static, {hard, module, tag, purge_requests}). -record(cpc_kill, {outstanding = [], no_outstanding = 0, waiting = [], killed = false}). -check_proc_code(Pids, Mod, Hard) -> +check_proc_code(Pids, Mod, Hard, PReqs) -> Tag = erlang:make_ref(), CpcS = #cpc_static{hard = Hard, module = Mod, - tag = Tag}, - check_proc_code(CpcS, cpc_init(CpcS, Pids, 0), 0, [], #cpc_kill{}, true). - -check_proc_code(#cpc_static{hard = true}, 0, 0, [], - #cpc_kill{outstanding = [], waiting = [], killed = Killed}, - true) -> - %% No outstanding requests. We did a hard check, so result is whether or - %% not we killed any processes... - Killed; -check_proc_code(#cpc_static{hard = false}, 0, 0, [], _KillState, Success) -> - %% No outstanding requests and we did a soft check... - Success; -check_proc_code(#cpc_static{hard = false, tag = Tag} = CpcS, NoReq0, NoGcReq0, - [], _KillState, false) -> - %% Failed soft check; just cleanup the remaining replies corresponding - %% to the requests we've sent... - {NoReq1, NoGcReq1} = receive - {check_process_code, {Tag, _P, GC}, _Res} -> - case GC of - false -> {NoReq0-1, NoGcReq0}; - true -> {NoReq0, NoGcReq0-1} - end - end, - check_proc_code(CpcS, NoReq1, NoGcReq1, [], _KillState, false); -check_proc_code(#cpc_static{tag = Tag} = CpcS, NoReq0, NoGcReq0, NeedGC0, - KillState0, Success) -> - - %% Check if we should request a GC operation - {NoGcReq1, NeedGC1} = case NoGcReq0 < ?MAX_CPC_GC_PROCS of - GcOpAllowed when GcOpAllowed == false; - NeedGC0 == [] -> - {NoGcReq0, NeedGC0}; - _ -> - {NoGcReq0+1, cpc_request_gc(CpcS,NeedGC0)} - end, - - %% Wait for a cpc reply or 'DOWN' message - {NoReq1, NoGcReq2, Pid, Result, KillState1} = cpc_recv(Tag, - NoReq0, - NoGcReq1, - KillState0), - - %% Check the result of the reply - case Result of - aborted -> - %% Operation aborted due to the need to GC in order to - %% determine if the process is referring the module. - %% Schedule the operation for restart allowing GC... - check_proc_code(CpcS, NoReq1, NoGcReq2, [Pid|NeedGC1], KillState1, - Success); - false -> + tag = Tag, + purge_requests = PReqs}, + cpc_receive(CpcS, cpc_init(CpcS, Pids, 0), #cpc_kill{}, []). + +cpc_receive(#cpc_static{hard = true} = CpcS, + 0, + #cpc_kill{outstanding = [], waiting = [], killed = Killed}, + PReqs) -> + %% No outstanding cpc requests. We did a hard check, so result is + %% whether or not we killed any processes... + cpc_result(CpcS, PReqs, Killed); +cpc_receive(#cpc_static{hard = false} = CpcS, 0, _KillState, PReqs) -> + %% No outstanding cpc requests and we did a soft check that succeeded... + cpc_result(CpcS, PReqs, complete); +cpc_receive(#cpc_static{tag = Tag} = CpcS, NoReq, KillState0, PReqs) -> + receive + {check_process_code, {Tag, _Pid}, false} -> %% Process not referring the module; done with this process... - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, KillState1, - Success); - true -> + cpc_receive(CpcS, NoReq-1, KillState0, PReqs); + {check_process_code, {Tag, Pid}, true} -> %% Process referring the module... case CpcS#cpc_static.hard of false -> %% ... and soft check. The whole operation failed so - %% no point continuing; clean up and fail... - check_proc_code(CpcS, NoReq1, NoGcReq2, [], KillState1, - false); + %% no point continuing; fail straight away. Garbage + %% messages from this session will be ignored + %% by following sessions... + cpc_result(CpcS, PReqs, abort); true -> %% ... and hard check; schedule kill of it... - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, - cpc_sched_kill(Pid, KillState1), Success) + KillState1 = cpc_sched_kill(Pid, KillState0), + cpc_receive(CpcS, NoReq-1, KillState1, PReqs) end; - 'DOWN' -> - %% Handled 'DOWN' message - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, - KillState1, Success) + {'DOWN', MonRef, process, _, _} -> + KillState1 = cpc_handle_down(MonRef, KillState0), + cpc_receive(CpcS, NoReq, KillState1, PReqs); + PReq when element(1, PReq) == purge; + element(1, PReq) == soft_purge; + element(1, PReq) == test_purge -> + %% A new purge request; save it until later... + cpc_receive(CpcS, NoReq, KillState0, [PReq | PReqs]); + _Garbage -> + %% Garbage message; ignore it... + cpc_receive(CpcS, NoReq, KillState0, PReqs) end. -cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = []} = KillState) -> - receive - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) - end; -cpc_recv(Tag, NoReq, NoGcReq, - #cpc_kill{outstanding = [R0, R1, R2, R3, R4 | _]} = KillState) -> - receive - {'DOWN', R, process, _, _} when R == R0; - R == R1; - R == R2; - R == R3; - R == R4 -> - cpc_handle_down(NoReq, NoGcReq, R, KillState); - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) - end; -cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = [R|_]} = KillState) -> - receive - {'DOWN', R, process, _, _} -> - cpc_handle_down(NoReq, NoGcReq, R, KillState); - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) +cpc_result(#cpc_static{purge_requests = PReqs}, NewPReqs, Res) -> + {Res, PReqs ++ cpc_reverse(NewPReqs)}. + +cpc_reverse([_] = L) -> L; +cpc_reverse(Xs) -> cpc_reverse(Xs, []). + +cpc_reverse([], Ys) -> Ys; +cpc_reverse([X|Xs], Ys) -> cpc_reverse(Xs, [X|Ys]). + +cpc_handle_down(R, #cpc_kill{outstanding = Rs, + no_outstanding = N} = KillState0) -> + try + NewOutst = cpc_list_rm(R, Rs), + KillState1 = KillState0#cpc_kill{outstanding = NewOutst, + no_outstanding = N-1}, + cpc_sched_kill_waiting(KillState1) + catch + throw : undefined -> %% Triggered by garbage message... + KillState0 end. -cpc_handle_down(NoReq, NoGcReq, R, #cpc_kill{outstanding = Rs, - no_outstanding = N} = KillState) -> - {NoReq, NoGcReq, undefined, 'DOWN', - cpc_sched_kill_waiting(KillState#cpc_kill{outstanding = cpc_list_rm(R, Rs), - no_outstanding = N-1})}. - +cpc_list_rm(_R, []) -> + throw(undefined); cpc_list_rm(R, [R|Rs]) -> Rs; cpc_list_rm(R0, [R1|Rs]) -> [R1|cpc_list_rm(R0, Rs)]. -cpc_handle_cpc(NoReq, NoGcReq, false, Pid, Res, KillState) -> - {NoReq-1, NoGcReq, Pid, Res, KillState}; -cpc_handle_cpc(NoReq, NoGcReq, true, Pid, Res, KillState) -> - {NoReq, NoGcReq-1, Pid, Res, KillState}. - cpc_sched_kill_waiting(#cpc_kill{waiting = []} = KillState) -> KillState; cpc_sched_kill_waiting(#cpc_kill{outstanding = Rs, @@ -343,18 +297,13 @@ cpc_sched_kill(Pid, no_outstanding = N+1, killed = true}. -cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid, AllowGc) -> - erts_internal:check_process_code(Pid, Mod, [{async, {Tag, Pid, AllowGc}}, - {allow_gc, AllowGc}]). - -cpc_request_gc(CpcS, [Pid|Pids]) -> - cpc_request(CpcS, Pid, true), - Pids. +cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid) -> + erts_internal:check_process_code(Pid, Mod, [{async, {Tag, Pid}}]). cpc_init(_CpcS, [], NoReqs) -> NoReqs; cpc_init(CpcS, [Pid|Pids], NoReqs) -> - cpc_request(CpcS, Pid, false), + cpc_request(CpcS, Pid), cpc_init(CpcS, Pids, NoReqs+1). % end of check_proc_code() implementation. @@ -366,64 +315,63 @@ cpc_init(CpcS, [Pid|Pids], NoReqs) -> %% as usual, but the tester can control when to enter the %% specific phases. %% -do_test_purge(Mod, From, Type, Ref) when Type == true; Type == false -> - Mon = erlang:monitor(process, From), - Res = case Type of - true -> do_test_hard_purge(Mod, From, Ref, Mon); - false -> do_test_soft_purge(Mod, From, Ref, Mon) - end, +do_test_purge(Mod, From, true, Ref, Reqs) -> + {Res, NewReqs} = do_test_hard_purge(Mod, From, Ref, Reqs), + From ! {test_purge, Res, Ref}, + NewReqs; +do_test_purge(Mod, From, false, Ref, Reqs) -> + {Res, NewReqs} = do_test_soft_purge(Mod, From, Ref, Reqs), From ! {test_purge, Res, Ref}, - erlang:demonitor(Mon, [flush]), - ok; -do_test_purge(_, _, _, _) -> - ok. + NewReqs; +do_test_purge(_, _, _, _, Reqs) -> + Reqs. -do_test_soft_purge(Mod, From, Ref, Mon) -> +do_test_soft_purge(Mod, From, Ref, Reqs) -> PrepRes = erts_internal:purge_module(Mod, prepare), - TestRes = test_progress(started, From, Mon, Ref, ok), + TestRes = test_progress(started, From, Ref, ok), case PrepRes of false -> - _ = test_progress(continued, From, Mon, Ref, TestRes), - true; + _ = test_progress(continued, From, Ref, TestRes), + {true, Reqs}; true -> - Res = check_proc_code(erlang:processes(), Mod, false), - _ = test_progress(continued, From, Mon, Ref, TestRes), - erts_internal:purge_module(Mod, - case Res of - false -> abort; - true -> complete - end) + {PurgeOp, NewReqs} = check_proc_code(erlang:processes(), + Mod, false, Reqs), + _ = test_progress(continued, From, Ref, TestRes), + {erts_internal:purge_module(Mod, PurgeOp), NewReqs} end. -do_test_hard_purge(Mod, From, Ref, Mon) -> +do_test_hard_purge(Mod, From, Ref, Reqs) -> PrepRes = erts_internal:purge_module(Mod, prepare), - TestRes = test_progress(started, From, Mon, Ref, ok), + TestRes = test_progress(started, From, Ref, ok), case PrepRes of false -> - _ = test_progress(continued, From, Mon, Ref, TestRes), - {false, false}; + _ = test_progress(continued, From, Ref, TestRes), + {{false, false}, Reqs}; true -> - DidKill = check_proc_code(erlang:processes(), Mod, true), - _ = test_progress(continued, From, Mon, Ref, TestRes), + {DidKill, NewReqs} = check_proc_code(erlang:processes(), + Mod, true, Reqs), + _ = test_progress(continued, From, Ref, TestRes), true = erts_internal:purge_module(Mod, complete), - {true, DidKill} + {{true, DidKill}, NewReqs} end. -test_progress(_State, _From, _Mon, _Ref, died) -> +test_progress(_State, _From, _Ref, died) -> %% Test process died; continue so we wont %% leave the system in an inconsistent %% state... died; -test_progress(started, From, Mon, Ref, ok) -> +test_progress(started, From, Ref, ok) -> From ! {started, Ref}, + Mon = erlang:monitor(process, From), receive {'DOWN', Mon, process, From, _} -> died; - {continue, Ref} -> ok + {continue, Ref} -> erlang:demonitor(Mon, [flush]), ok end; -test_progress(continued, From, Mon, Ref, ok) -> +test_progress(continued, From, Ref, ok) -> From ! {continued, Ref}, + Mon = erlang:monitor(process, From), receive {'DOWN', Mon, process, From, _} -> died; - {complete, Ref} -> ok + {complete, Ref} -> erlang:demonitor(Mon, [flush]), ok end. diff --git a/erts/preloaded/src/erts_dirty_process_code_checker.erl b/erts/preloaded/src/erts_dirty_process_code_checker.erl index 911642082c..7d3fa264be 100644 --- a/erts/preloaded/src/erts_dirty_process_code_checker.erl +++ b/erts/preloaded/src/erts_dirty_process_code_checker.erl @@ -48,8 +48,7 @@ handle_request({Requester, Prio, {check_process_code, ReqId, - Module, - _Flags} = Op}) -> + Module} = Op}) -> %% %% Target may have stopped executing dirty since the %% initial request was made. Check its current state diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index f4518c4008..26fb1458af 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2016. All Rights Reserved. +%% Copyright Ericsson AB 2012-2017. 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. @@ -31,7 +31,8 @@ -export([await_port_send_result/3]). -export([cmp_term/2]). --export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1]). +-export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1, + maps_to_list/2]). -export([open_port/2, port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -39,6 +40,7 @@ gather_system_check_result/1]). -export([request_system_task/3, request_system_task/4]). +-export([garbage_collect/1]). -export([check_process_code/3]). -export([check_dirty_process_code/2]). @@ -60,7 +62,7 @@ -export([trace/3, trace_pattern/3]). %% Auto import name clash --export([check_process_code/2]). +-export([check_process_code/1]). %% %% Await result of send to port @@ -205,8 +207,9 @@ port_info(_Result, _Item) -> -spec request_system_task(Pid, Prio, Request) -> 'ok' when Prio :: 'max' | 'high' | 'normal' | 'low', - Request :: {'garbage_collect', term()} - | {'check_process_code', term(), module(), non_neg_integer()} + Type :: 'major' | 'minor', + Request :: {'garbage_collect', term(), Type} + | {'check_process_code', term(), module()} | {'copy_literals', term(), boolean()}, Pid :: pid(). @@ -216,7 +219,7 @@ request_system_task(_Pid, _Prio, _Request) -> -spec request_system_task(RequesterPid, TargetPid, Prio, Request) -> 'ok' | 'dirty_execution' when Prio :: 'max' | 'high' | 'normal' | 'low', Request :: {'garbage_collect', term()} - | {'check_process_code', term(), module(), non_neg_integer()} + | {'check_process_code', term(), module()} | {'copy_literals', term(), boolean()}, RequesterPid :: pid(), TargetPid :: pid(). @@ -224,12 +227,14 @@ request_system_task(_Pid, _Prio, _Request) -> request_system_task(_RequesterPid, _TargetPid, _Prio, _Request) -> erlang:nif_error(undefined). --define(ERTS_CPC_ALLOW_GC, (1 bsl 0)). +-spec garbage_collect(Mode) -> 'true' when Mode :: 'major' | 'minor'. --spec check_process_code(Module, Flags) -> boolean() when - Module :: module(), - Flags :: non_neg_integer(). -check_process_code(_Module, _Flags) -> +garbage_collect(_Mode) -> + erlang:nif_error(undefined). + +-spec check_process_code(Module) -> boolean() when + Module :: module(). +check_process_code(_Module) -> erlang:nif_error(undefined). -spec check_process_code(Pid, Module, OptionList) -> CheckResult | async when @@ -240,7 +245,7 @@ check_process_code(_Module, _Flags) -> OptionList :: [Option], CheckResult :: boolean() | aborted. check_process_code(Pid, Module, OptionList) -> - {Async, Flags} = get_cpc_opts(OptionList, sync, ?ERTS_CPC_ALLOW_GC), + Async = get_cpc_opts(OptionList, sync), case Async of {async, ReqId} -> {priority, Prio} = erlang:process_info(erlang:self(), @@ -249,13 +254,12 @@ check_process_code(Pid, Module, OptionList) -> Prio, {check_process_code, ReqId, - Module, - Flags}), + Module}), async; sync -> case Pid == erlang:self() of true -> - erts_internal:check_process_code(Module, Flags); + erts_internal:check_process_code(Module); false -> {priority, Prio} = erlang:process_info(erlang:self(), priority), @@ -264,8 +268,7 @@ check_process_code(Pid, Module, OptionList) -> Prio, {check_process_code, ReqId, - Module, - Flags}), + Module}), receive {check_process_code, ReqId, CheckResult} -> CheckResult @@ -273,18 +276,14 @@ check_process_code(Pid, Module, OptionList) -> end end. -% gets async and flag opts and verify valid option list -get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, Flags) -> - get_cpc_opts(Options, AsyncTuple, Flags); -get_cpc_opts([{allow_gc, AllowGC} | Options], Async, Flags) -> - get_cpc_opts(Options, Async, cpc_flags(Flags, ?ERTS_CPC_ALLOW_GC, AllowGC)); -get_cpc_opts([], Async, Flags) -> - {Async, Flags}. - -cpc_flags(OldFlags, Bit, true) -> - OldFlags bor Bit; -cpc_flags(OldFlags, Bit, false) -> - OldFlags band (bnot Bit). +% gets async opt and verify valid option list +get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync) -> + get_cpc_opts(Options, AsyncTuple); +get_cpc_opts([{allow_gc, AllowGC} | Options], Async) when AllowGC == true; + AllowGC == false -> + get_cpc_opts(Options, Async); +get_cpc_opts([], Async) -> + Async. -spec check_dirty_process_code(Pid,Module) -> 'true' | 'false' when Pid :: pid(), @@ -371,6 +370,15 @@ map_hashmap_children(_M) -> Multi :: boolean(), Res :: term(). +%% return a list of key value pairs, at most of length N +-spec maps_to_list(M,N) -> Pairs when + M :: map(), + N :: integer(), + Pairs :: list(). + +maps_to_list(_M, _N) -> + erlang:nif_error(undefined). + %% erlang:demonitor(Ref, [flush]) traps to %% erts_internal:flush_monitor_messages(Ref, Res) when %% it needs to flush monitor messages. diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 551ca4ea40..1ccf8d599f 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -263,21 +263,30 @@ boot(Start,Flags,Args) -> boot_loop(BootPid,State). %%% Convert a term to a printable string, if possible. -to_string(X) when is_list(X) -> % assume string +to_string(X, D) when is_list(X), D < 4 -> % assume string F = flatten(X, []), case printable_list(F) of - true -> F; - false -> "" + true when length(F) > 0 -> F; + _false -> + List = [to_string(E, D+1) || E <- X], + flatten(["[",join(List),"]"], []) end; -to_string(X) when is_atom(X) -> +to_string(X, _D) when is_list(X) -> + "[_]"; +to_string(X, _D) when is_atom(X) -> atom_to_list(X); -to_string(X) when is_pid(X) -> +to_string(X, _D) when is_pid(X) -> pid_to_list(X); -to_string(X) when is_float(X) -> +to_string(X, _D) when is_float(X) -> float_to_list(X); -to_string(X) when is_integer(X) -> +to_string(X, _D) when is_integer(X) -> integer_to_list(X); -to_string(_X) -> +to_string(X, D) when is_tuple(X), D < 4 -> + List = [to_string(E, D+1) || E <- tuple_to_list(X)], + flatten(["{",join(List),"}"], []); +to_string(X, _D) when is_tuple(X) -> + "{_}"; +to_string(_X, _D) -> "". % can't do anything with it %% This is an incorrect and narrow definition of printable characters. @@ -291,6 +300,13 @@ printable_list([$\t|T]) -> printable_list(T); printable_list([]) -> true; printable_list(_) -> false. +join([] = T) -> + T; +join([_Elem] = T) -> + T; +join([Elem|T]) -> + [Elem,","|join(T)]. + flatten([H|T], Tail) when is_list(H) -> flatten(H, flatten(T, Tail)); flatten([H|T], Tail) -> @@ -299,7 +315,7 @@ flatten([], Tail) -> Tail. things_to_string([X|Rest]) -> - " (" ++ to_string(X) ++ ")" ++ things_to_string(Rest); + " (" ++ to_string(X, 0) ++ ")" ++ things_to_string(Rest); things_to_string([]) -> "". @@ -307,9 +323,8 @@ halt_string(String, List) -> String ++ things_to_string(List). %% String = string() -%% List = [string() | atom() | pid() | number()] -%% Any other items in List, such as tuples, are ignored when creating -%% the string used as argument to erlang:halt/1. +%% List = [string() | atom() | pid() | number() | list() | tuple()] +%% Items in List are truncated if found to be too large -spec crash(_, _) -> no_return(). crash(String, List) -> halt(halt_string(String, List)). @@ -674,16 +689,8 @@ do_unload([M|Mods]) -> catch erlang:purge_module(M), do_unload(Mods); do_unload([]) -> - purge_all_hipe_refs(), ok. -purge_all_hipe_refs() -> - case erlang:system_info(hipe_architecture) of - undefined -> ok; - _ -> hipe_bifs:remove_refs_from(all) - end. - - sub([H|T],L) -> sub(T,del(H,L)); sub([],L) -> L. @@ -932,15 +939,15 @@ load_rest([], _) -> prepare_loading_fun() -> fun(Mod, FullName, Beam) -> case erlang:prepare_loading(Mod, Beam) of - Prepared when is_binary(Prepared) -> + {error,_}=Error -> + Error; + Prepared -> case erlang:has_prepared_code_on_load(Prepared) of true -> {ok,{on_load,Beam,FullName}}; false -> {ok,{prepared,Prepared,FullName}} - end; - {error,_}=Error -> - Error + end end end. @@ -1084,7 +1091,7 @@ start_it({eval,Bin}) -> {ok,Ts,_} = erl_scan:string(Str), Ts1 = case reverse(Ts) of [{dot,_}|_] -> Ts; - TsR -> reverse([{dot,1} | TsR]) + TsR -> reverse([{dot,erl_anno:new(1)} | TsR]) end, {ok,Expr} = erl_parse:parse_exprs(Ts1), {value, _Value, _Bs} = erl_eval:exprs(Expr, erl_eval:new_bindings()), diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 61f727e8a4..017a706a8b 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2017. 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. @@ -1234,6 +1234,7 @@ enc_opt(netns) -> ?INET_LOPT_NETNS; enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM; enc_opt(raw) -> ?INET_OPT_RAW; +enc_opt(bind_to_device) -> ?INET_OPT_BIND_TO_DEVICE; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; enc_opt(sctp_associnfo) -> ?SCTP_OPT_ASSOCINFO; @@ -1294,6 +1295,7 @@ dec_opt(?INET_LOPT_NETNS) -> netns; dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter; dec_opt(?INET_OPT_RAW) -> raw; +dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device; dec_opt(I) when is_integer(I) -> undefined. @@ -1395,6 +1397,7 @@ type_opt_1(packet_size) -> uint; type_opt_1(read_packets) -> uint; type_opt_1(netns) -> binary; type_opt_1(show_econnreset) -> bool; +type_opt_1(bind_to_device) -> binary; %% %% SCTP options (to be set). If the type is a record type, the corresponding %% record signature is returned, otherwise, an "elementary" type tag diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index fa0f28c5c3..8cd3e39fd7 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -23,7 +23,8 @@ -export([open/0,close/1,deflateInit/1,deflateInit/2,deflateInit/6, deflateSetDictionary/2,deflateReset/1,deflateParams/3, deflate/2,deflate/3,deflateEnd/1, - inflateInit/1,inflateInit/2,inflateSetDictionary/2, + inflateInit/1,inflateInit/2, + inflateSetDictionary/2,inflateGetDictionary/1, inflateSync/1,inflateReset/1,inflate/2,inflateEnd/1, inflateChunk/1, inflateChunk/2, setBufSize/2,getBufSize/1, @@ -98,25 +99,26 @@ -define(INFLATE_INIT, 8). -define(INFLATE_INIT2, 9). -define(INFLATE_SETDICT, 10). --define(INFLATE_SYNC, 11). --define(INFLATE_RESET, 12). --define(INFLATE_END, 13). --define(INFLATE, 14). --define(INFLATE_CHUNK, 25). +-define(INFLATE_GETDICT, 11). +-define(INFLATE_SYNC, 12). +-define(INFLATE_RESET, 13). +-define(INFLATE_END, 14). +-define(INFLATE, 15). +-define(INFLATE_CHUNK, 26). --define(CRC32_0, 15). --define(CRC32_1, 16). --define(CRC32_2, 17). +-define(CRC32_0, 16). +-define(CRC32_1, 17). +-define(CRC32_2, 18). --define(SET_BUFSZ, 18). --define(GET_BUFSZ, 19). --define(GET_QSIZE, 20). +-define(SET_BUFSZ, 19). +-define(GET_BUFSZ, 20). +-define(GET_QSIZE, 21). --define(ADLER32_1, 21). --define(ADLER32_2, 22). +-define(ADLER32_1, 22). +-define(ADLER32_2, 23). --define(CRC32_COMBINE, 23). --define(ADLER32_COMBINE, 24). +-define(CRC32_COMBINE, 24). +-define(ADLER32_COMBINE, 25). %%------------------------------------------------------------------------ @@ -242,6 +244,13 @@ inflateInit(Z, WindowBits) -> inflateSetDictionary(Z, Dictionary) -> call(Z, ?INFLATE_SETDICT, Dictionary). +-spec inflateGetDictionary(Z) -> Dictionary when + Z :: zstream(), + Dictionary :: iolist(). +inflateGetDictionary(Z) -> + _ = call(Z, ?INFLATE_GETDICT, []), + collect(Z). + -spec inflateSync(zstream()) -> 'ok'. inflateSync(Z) -> call(Z, ?INFLATE_SYNC, []). |