From 0da4f156c87d9afd00d65c96f8a9c6e1c9616b9a Mon Sep 17 00:00:00 2001 From: lucioleKi Date: Thu, 28 Nov 2024 12:08:23 +0100 Subject: [PATCH] erts: Add BIFs `processes_first/0` and `processes_next/1` This PR adds 2 BIFs to the `erlang` module. `processes_first/0` returns a process iterator that can be used to iterate through the process table. `process_next/1` takes in a process iterator and returns a 2-tuple, consisting of one process identifier and a new process iterator. If the process iterator runs out of processes in the process table, `none` will be returned. By using these 2 BIFs instead of `processes/0`, one can avoid creating a potentially huge list of the pids for all existing processes, at the cost of less consistency guarantees. Process identifiers returned from consecutive calls of `process_next/1` may not be a consistent snapshot of all elements existing in the table during any of the calls. --- erts/emulator/beam/bif.c | 18 ++++++++ erts/emulator/beam/bif.tab | 1 + erts/emulator/beam/erl_ptab.c | 55 +++++++++++++++++++++++ erts/emulator/beam/erl_ptab.h | 3 ++ erts/emulator/test/exception_SUITE.erl | 4 ++ erts/emulator/test/process_SUITE.erl | 40 +++++++++++++++-- erts/preloaded/ebin/erlang.beam | Bin 40020 -> 40364 bytes erts/preloaded/ebin/erts_internal.beam | Bin 10000 -> 10052 bytes erts/preloaded/src/erlang.erl | 60 +++++++++++++++++++++++++ erts/preloaded/src/erts_internal.erl | 6 +++ lib/kernel/src/erl_erts_errors.erl | 2 + lib/tools/emacs/erlang.el | 2 + 12 files changed, 188 insertions(+), 3 deletions(-) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index a32186da8a40..5709df04b2eb 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3825,6 +3825,24 @@ BIF_RETTYPE processes_0(BIF_ALIST_0) return erts_ptab_list(BIF_P, &erts_proc); } +/**********************************************************************/ +/* + * The erts_internal:processes_next/1 BIF. + */ + +BIF_RETTYPE erts_internal_processes_next_1(BIF_ALIST_1) +{ + Eterm res; + if (is_not_small(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + res = erts_ptab_processes_next(BIF_P, &erts_proc, unsigned_val(BIF_ARG_1)); + if (is_non_value(res)) { + BIF_ERROR(BIF_P, BADARG); + } + BIF_RET(res); +} + /**********************************************************************/ /* * The erlang:ports/0 BIF. diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index c7aa2bff1c78..45c59fe9acb0 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -807,3 +807,4 @@ bif erts_trace_cleaner:send_trace_clean_signal/1 # bif erts_internal:system_monitor/1 bif erts_internal:system_monitor/3 +bif erts_internal:processes_next/1 diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index 37408860918c..4e9688db59af 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1465,6 +1465,61 @@ ptab_pix2el(ErtsPTab *ptab, int ix) return ptab_el; } +#define ERTS_PTAB_REDS_MULTIPLIER 25 + +Eterm +erts_ptab_processes_next(Process *c_p, ErtsPTab *ptab, Uint first) +{ + Uint i; + int scanned; + Sint limit; + Uint need; + Eterm res; + Eterm* hp; + Eterm *hp_end; + + int max_pids = MAX(ERTS_BIF_REDS_LEFT(c_p), 1); + int num_pids = 0; + int n = max_pids * ERTS_PTAB_REDS_MULTIPLIER; + limit = MIN(ptab->r.o.max, first+n); + + if (first == limit) { + return am_none; + } else if (first > limit) { + return THE_NON_VALUE; + } + + need = n * 2; + hp = HAlloc(c_p, need); /* we need two heap words for each id */ + hp_end = hp + need; + res = make_list(hp); + + for (i = first; i < limit && num_pids < max_pids; i++) { + ErtsPTabElementCommon *el = ptab_pix2el(ptab, i); + if (el) { + hp[0] = el->id; + hp[1] = make_list(hp+2); + hp += 2; + num_pids++; + } + } + + if (num_pids == 0) { + res = NIL; + } else { + hp[-1] = NIL; + } + + scanned = (i - first) / ERTS_PTAB_REDS_MULTIPLIER + 1; + + res = TUPLE2(hp, make_small(i), res); + HRelease(c_p, hp_end, hp); + + BUMP_REDS(c_p, scanned); + + return res; +} + Eterm erts_debug_ptab_list(Process *c_p, ErtsPTab *ptab) { diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h index 8753ae9365e2..a53475152e2a 100644 --- a/erts/emulator/beam/erl_ptab.h +++ b/erts/emulator/beam/erl_ptab.h @@ -474,6 +474,9 @@ ERTS_GLB_INLINE int erts_lc_ptab_is_rwlocked(ErtsPTab *ptab) BIF_RETTYPE erts_ptab_list(struct process *c_p, ErtsPTab *ptab); +BIF_RETTYPE erts_ptab_processes_next(struct process *c_p, ErtsPTab *ptab, + Uint first); + #endif #if defined(ERTS_PTAB_WANT_DEBUG_FUNCS__) && !defined(ERTS_PTAB_DEBUG_FUNCS__) diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl index e632a5ac98b1..d72cc86eb0b3 100644 --- a/erts/emulator/test/exception_SUITE.erl +++ b/erts/emulator/test/exception_SUITE.erl @@ -1108,6 +1108,10 @@ error_info(_Config) -> {process_display, [ExternalPid, whatever]}, {process_display, [DeadProcess, backtrace]}, + {processes_next, [{a, []}]}, + {processes_next, [{-1, []}]}, + {processes_next, [a]}, + {process_flag, [trap_exit, some_value]}, {process_flag, [bad_flag, some_value]}, diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 9680eb5836fd..705dbdf30678 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -103,7 +103,8 @@ demonitor_aliasmonitor/1, down_aliasmonitor/1, monitor_tag/1, - no_pid_wrap/1]). + no_pid_wrap/1, + processes_iter/1]). -export([prio_server/2, prio_client/2, init/1, handle_event/2]). @@ -163,7 +164,8 @@ groups() -> processes_small_tab, processes_this_tab, processes_last_call_trap, processes_apply_trap, processes_gc_trap, processes_term_proc_list, - processes_send_infant]}, + processes_send_infant, + processes_iter]}, {process_info_bif, [], [t_process_info, process_info_messages, process_info_other, process_info_other_msg, @@ -2513,7 +2515,14 @@ processes_bif_test() -> processes() end, + IterProcesses = + fun () -> + erts_debug:set_internal_state(reds_left, WantReds), + iter_all_processes() + end, + ok = do_processes_bif_test(WantReds, WillTrap, Processes), + ok = do_processes_bif_test(WantReds, false, IterProcesses()), case WillTrap of false -> @@ -2550,7 +2559,19 @@ processes_bif_test() -> undefined -> ok; Comment -> {comment, Comment} end. - + +iter_all_processes() -> + Iter = erlang:processes_first(), + iter_all_processes(Iter). + +iter_all_processes(Iter0) -> + case erlang:processes_next(Iter0) of + {Pid, Iter} -> + [Pid|iter_all_processes(Iter)]; + none -> + none + end. + do_processes_bif_test(WantReds, DieTest, Processes) -> Tester = self(), SpawnProcesses = fun (Prio) -> @@ -4199,6 +4220,19 @@ processes_term_proc_list(Config) when is_list(Config) -> ok. +processes_iter(Config) when is_list(Config) -> + ProcessLimit = erlang:system_info(process_limit), + {'EXIT',{badarg,_}} = catch erts_internal:processes_next(ProcessLimit + 1), + {'EXIT',{badarg,_}} = catch erts_internal:processes_next(-1), + {'EXIT',{badarg,_}} = catch erts_internal:processes_next(1 bsl 32), + {'EXIT',{badarg,_}} = catch erts_internal:processes_next(1 bsl 64), + {'EXIT',{badarg,_}} = catch erts_internal:processes_next(abc), + + none = erts_internal:processes_next(ProcessLimit), + + ok. + + %% OTP-18322: Send msg to spawning process pid returned from processes/0 processes_send_infant(_Config) -> case erlang:system_info(schedulers_online) of diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index aed9bed6838349c5fb5c2d61bf304db0043e8170..8548c3b7a7f0790e45cd6bf1054da0a5b5eba71e 100644 GIT binary patch delta 21608 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 delta 21246 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 delta 680 zcmYL{TS$~~5XHZ5bz}buW$HtkkY?IWYo-QytMHQPlot|>=mvQ|WNK(6rER68(^c|8 zH_9?2=t7~JB-(}2Fe=li>A_R&}b&s$2D_el?&TsE2A;JyxS?OubQW)mQb6X44!B zpg>wgVMMfqB54`LQ9P}rG|HfS+DZjfNTpOp6;w$zWUr-qIzSE7NJprNgicaBIp_j) z(ha&vx2cZ?X^2MXIlZ9w^od+FMbm6%Kc3IQ9KvB7&NhzVNRHwdUe2+cz=@pB8Jxqp zypcC?0T=QvuHZVZ=i_{W+qj)O_&i_aF1}*t9`5CSe#CeADL>;;9^=UYHAC1RxN>2thckSbSv z;~iZ1f(cBDE++AkPzjQGVv`7olqiXjRkB)AWsRguhGa^XKl%PDDTon=~T_MDlSDRIV`T$WawcTiAjWs#8v|9s>5KJEk<)nlY1(dgyQ zBJTiyn`ZL$a%j3WF3Hy;+sCp{x5hjEdOo@}A<4tfZ3kOIJ&X(Iodr%k`iw!kA&Vh5 do6>5l@-)q}#o!%=9EOa&p74(~=k<_w^B;u{<8}Z5 diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 3c950c0a2f53..4fdef2a44769 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -265,6 +265,7 @@ A timeout value that can be passed to a -export_type([message_queue_data/0]). -export_type([monitor_option/0]). -export_type([stacktrace/0]). +-export_type([processes_iter_ref/0]). -type stacktrace_extrainfo() :: {line, pos_integer()} | @@ -465,6 +466,7 @@ A list of binaries. This datatype is useful to use together with -export([time_offset/0, time_offset/1, timestamp/0]). -export([process_display/2]). -export([process_flag/3, process_info/1, processes/0, purge_module/1]). +-export([processes_first/0, processes_next/1]). -export([put/2, raise/3, read_timer/1, read_timer/2, ref_to_list/1, register/2]). -export([send_after/3, send_after/4, start_timer/3, start_timer/4]). -export([registered/0, resume_process/1, round/1, self/0]). @@ -5219,6 +5221,64 @@ Example: processes() -> erlang:nif_error(undefined). +%% The process iterator is a 2-tuple, consisting of an index to the process +%% table and a list of process identifiers that existed when the last scan of +%% the process table took place. The index is the starting place for the next +%% scan of the process table. +-opaque processes_iter_ref() :: {integer(), [pid()]}. + +%% processes_first/0 +-doc """ +Returns a processes iterator that can be used in +[`processes_next/1`](`processes_next/1`). +""". +-doc #{ group => processes }. +-spec processes_first() -> processes_iter_ref(). +processes_first() -> + {0, []}. + +%% processes_next/1 +-doc """ +Returns a 2-tuple, consisting of one process identifier and a new processes +iterator. If the process iterator has run out of processes in the process table, +`none` will be returned. + +Example: + +```erlang +> I0 = erlang:processes_first(), ok. +ok +> {Pid1, I1} = erlang:processes_next(I0), Pid1. +<0.0.0>, +> {Pid2, I2} = erlang:processes_next(I1), Pid2. +<0.1.0> +``` + +> #### Note {: .info } +> +> This BIF has less consistency guarantee than [`processes/0`](`processes/0`). +> Process identifiers returned from consecutive calls of this BIF may not be a +> consistent snapshot of all elements existing in the table during any of the +> calls. +""". +-doc #{ group => processes }. +-spec processes_next(Iter) -> {Pid, NewIter} | 'none' when + Iter :: processes_iter_ref(), + NewIter :: processes_iter_ref(), + Pid :: pid(). +processes_next({IterRef, [Pid|Pids]}) -> + {Pid, {IterRef, Pids}}; +processes_next({IterRef0, []}=Arg) -> + try erts_internal:processes_next(IterRef0) of + none -> none; + {IterRef, [Pid|Pids]} -> {Pid, {IterRef, Pids}}; + {IterRef, []} -> processes_next({IterRef, []}) + catch error:badarg -> + badarg_with_info([Arg]) + end; +processes_next(Arg) -> + badarg_with_info([Arg]). + %% purge_module/1 -doc """ Removes old code for `Module`. Before this BIF is used, `check_process_code/2` diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index e0aaf5ee6af8..07a3c4b5ccd4 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -129,6 +129,8 @@ -export([system_monitor/1, system_monitor/3]). +-export([processes_next/1]). + %% %% Await result of send to port %% @@ -1166,3 +1168,7 @@ system_monitor(_Session) -> Return :: undefined | ok | {pid(), Options}. system_monitor(_Session, _MonitorPid, _Options) -> erlang:nif_error(undefined). + +-spec processes_next(integer()) -> {integer(), [pid()]} | 'none'. +processes_next(_IterRef) -> + erlang:nif_error(undefined). diff --git a/lib/kernel/src/erl_erts_errors.erl b/lib/kernel/src/erl_erts_errors.erl index 469907dac3df..33ac547d9179 100644 --- a/lib/kernel/src/erl_erts_errors.erl +++ b/lib/kernel/src/erl_erts_errors.erl @@ -733,6 +733,8 @@ format_erlang_error(process_display, [Pid,_], Cause) -> _ -> [must_be_local_pid(Pid, dead_process)] end; +format_erlang_error(processes_next, [_], _Cause) -> + [~"invalid processes iterator"]; format_erlang_error(process_flag, [_,_], Cause) -> case Cause of badopt -> diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index f582c198ad0a..3d580588b886 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -993,6 +993,8 @@ resulting regexp is surrounded by \\_< and \\_>." "posixtime_to_universaltime" "prepare_loading" "process_display" + "processes_first" + "processes_next" "raise" "read_timer" "resume_process"