From e2cb90bcbe8a25dcadfdf42b755a0d5c64fde1f9 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Tue, 14 Jan 2025 22:04:48 +0100 Subject: [PATCH] Fix driver usage of ports - Fix i2c and spi esp32 native code to use ports - Fix `whereis/1` and `register/2` to work with ports - Fix specifications related to ports - Fix documentation of `register/2` Signed-off-by: Paul Guyot --- UPDATING.md | 2 ++ libs/eavmlib/src/console.erl | 20 +++++------ libs/eavmlib/src/gpio.erl | 2 +- libs/eavmlib/src/i2c.erl | 2 +- libs/eavmlib/src/network.erl | 12 ++++--- libs/eavmlib/src/port.erl | 18 +++++----- libs/eavmlib/src/spi.erl | 6 ++-- libs/eavmlib/src/uart.erl | 17 +++++---- libs/estdlib/src/erlang.erl | 36 +++++++++++-------- src/libAtomVM/globalcontext.c | 17 ++++----- src/libAtomVM/globalcontext.h | 8 ++--- src/libAtomVM/nifs.c | 23 ++++++------ src/libAtomVM/opcodesswitch.h | 12 ++++--- src/platforms/emscripten/src/lib/sys.c | 6 +++- .../components/avm_builtins/gpio_driver.c | 19 +++++----- .../components/avm_builtins/i2c_driver.c | 8 ++--- .../components/avm_builtins/socket_driver.c | 6 ++-- .../components/avm_builtins/spi_driver.c | 2 +- src/platforms/stm32/src/lib/gpio_driver.c | 17 +++++---- tests/erlang_tests/test_regecho_driver.erl | 5 ++- 20 files changed, 129 insertions(+), 109 deletions(-) diff --git a/UPDATING.md b/UPDATING.md index 79c1d9a7b..23803b7ab 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -11,6 +11,8 @@ by using `term_port_from_local_process_id` instead of `term_from_local_process_id`. Sockets, from port socket driver, are also represented by a port and some matching code may need to be updated from `is_pid/1` to `is_port/1`. +- Ports and pids can be registered. Function `globalcontext_get_registered_process` result now is +a term that can be a `port()` or a `pid()`. ## v0.6.4 -> v0.6.5 diff --git a/libs/eavmlib/src/console.erl b/libs/eavmlib/src/console.erl index 05877ed89..92e3932af 100644 --- a/libs/eavmlib/src/console.erl +++ b/libs/eavmlib/src/console.erl @@ -40,7 +40,7 @@ %%----------------------------------------------------------------------------- -spec puts(iodata()) -> ok | {error, term()}. puts(Text) -> - puts(get_pid(), Text). + puts(get_port(), Text). %% @hidden -spec puts(pid(), iodata()) -> ok. @@ -55,7 +55,7 @@ puts(Console, Text) -> %%----------------------------------------------------------------------------- -spec flush() -> ok | {error, term()}. flush() -> - flush(get_pid()). + flush(get_port()). %% @hidden -spec flush(pid()) -> ok. @@ -77,18 +77,18 @@ print(_Text) -> %% Internal operations %% @private --spec get_pid() -> pid(). -get_pid() -> +-spec get_port() -> port(). +get_port() -> case whereis(console) of undefined -> start(); - Pid when is_pid(Pid) -> - Pid + Port when is_port(Port) -> + Port end. %% @private --spec start() -> pid(). +-spec start() -> port(). start() -> - Pid = erlang:open_port({spawn, "console"}, []), - erlang:register(console, Pid), - Pid. + Port = erlang:open_port({spawn, "console"}, []), + erlang:register(console, Port), + Port. diff --git a/libs/eavmlib/src/gpio.erl b/libs/eavmlib/src/gpio.erl index d0fac085a..8c120abfd 100644 --- a/libs/eavmlib/src/gpio.erl +++ b/libs/eavmlib/src/gpio.erl @@ -57,7 +57,7 @@ detach_interrupt/1 ]). --type gpio() :: pid(). +-type gpio() :: port(). %% This is the pid returned by `gpio:start/0'. -type pin() :: non_neg_integer() | pin_tuple(). %% The pin definition for ESP32 and PR2040 is a non-negative integer. A tuple is used on the STM32 platform and for the extra "WL" pins on the Pico-W. diff --git a/libs/eavmlib/src/i2c.erl b/libs/eavmlib/src/i2c.erl index b0dc3ad63..76260edd1 100644 --- a/libs/eavmlib/src/i2c.erl +++ b/libs/eavmlib/src/i2c.erl @@ -66,7 +66,7 @@ | {use_nif, boolean()} | {send_timeout_ms, non_neg_integer()}. -type params() :: [param()]. --type i2c() :: pid() | {'$i2c', term(), reference()}. +-type i2c() :: port() | {'$i2c', term(), reference()}. -type address() :: non_neg_integer(). -type register() :: non_neg_integer(). diff --git a/libs/eavmlib/src/network.erl b/libs/eavmlib/src/network.erl index 3f83ca82c..52b21707c 100644 --- a/libs/eavmlib/src/network.erl +++ b/libs/eavmlib/src/network.erl @@ -462,20 +462,22 @@ maybe_callback1({Key, Arg} = Msg, Config) -> end. %% @private +-spec get_port() -> port(). get_port() -> case whereis(network_port) of undefined -> open_port(); - Pid -> - Pid + Port -> + Port end. %% @private +-spec open_port() -> port(). open_port() -> - Pid = erlang:open_port({spawn, "network"}, []), + Port = erlang:open_port({spawn, "network"}, []), %Pid = spawn(?MODULE, simulation_loop, []), - erlang:register(network_port, Pid), - Pid. + erlang:register(network_port, Port), + Port. %% @private wait_for_ip(Timeout) -> diff --git a/libs/eavmlib/src/port.erl b/libs/eavmlib/src/port.erl index c781d5060..973c49d69 100644 --- a/libs/eavmlib/src/port.erl +++ b/libs/eavmlib/src/port.erl @@ -28,7 +28,7 @@ %% The port driver should be initialized with: %% `open_port({spawn, "Name"}, Param)' %% Where Name is an atom(), and is the name of the driver. The return from `open_port/2' -%% will be the Pid that will be required for future `port:call/2' or `port:call/3' use. +%% will be the Port that will be required for future `port:call/2' or `port:call/3' use. %% %% Examples: %% ```open_port({spawn, "i2c"}, Param)''' @@ -41,31 +41,31 @@ -export([call/2, call/3]). %%----------------------------------------------------------------------------- -%% @param Port Pid to which to send messages +%% @param Port Port to which to send messages %% @param Message the message to send %% @returns term() | {error, Reason}. -%% @doc Send a message to a given port driver pid. +%% @doc Send a message to a given port driver. %% -%% This function is used to send a message to an open port divers pid and will +%% This function is used to send a message to an open port drivers port and will %% return a term or `{error, Reason}'. %% @end %%----------------------------------------------------------------------------- --spec call(Port :: pid(), Message :: term()) -> term(). +-spec call(Port :: port(), Message :: term()) -> term(). call(Port, Message) -> call(Port, Message, infinity). %%----------------------------------------------------------------------------- -%% @param Port Pid to which to send messages +%% @param Port Port to which to send messages %% @param Message the message to send %% @param Timeout the timeout value in milliseconds %% @returns term() | {error, Reason}. -%% @doc Send a message to a given port driver pid with a timeout. +%% @doc Send a message to a given port driver with a timeout. %% -%% This function is used to send a message to an open port divers pid and will return +%% This function is used to send a message to an open port drivers port and will return %% a term or `{error, Reason}', or`{error, timeout}' if the TimeoutMs is reached first. %% @end %%----------------------------------------------------------------------------- --spec call(Port :: pid(), Message :: term(), Timeout :: timeout()) -> term() | {error, timeout}. +-spec call(Port :: port(), Message :: term(), Timeout :: timeout()) -> term() | {error, timeout}. call(Port, Message, Timeout) -> MonitorRef = monitor(port, Port), Port ! {'$call', {self(), MonitorRef}, Message}, diff --git a/libs/eavmlib/src/spi.erl b/libs/eavmlib/src/spi.erl index cf04c584c..b82593949 100644 --- a/libs/eavmlib/src/spi.erl +++ b/libs/eavmlib/src/spi.erl @@ -68,7 +68,7 @@ | {device_config, [{device_name(), device_config()}]} ]. --type spi() :: pid(). +-type spi() :: port(). -type address() :: non_neg_integer(). -type transaction() :: #{ @@ -244,7 +244,7 @@ write_at(SPI, DeviceName, Address, Len, Data) -> -spec write(SPI :: spi(), DeviceName :: device_name(), Transaction :: transaction()) -> ok | {error, Reason :: term()}. write(SPI, DeviceName, Transaction) when - is_pid(SPI) andalso is_atom(DeviceName) andalso is_map(Transaction) + is_port(SPI) andalso is_atom(DeviceName) andalso is_map(Transaction) -> port:call(SPI, {write, DeviceName, Transaction}). @@ -279,7 +279,7 @@ write(SPI, DeviceName, Transaction) when -spec write_read(SPI :: spi(), DeviceName :: device_name(), Transaction :: transaction()) -> {ok, ReadData :: binary()} | {error, Reason :: term()}. write_read(SPI, DeviceName, Transaction) when - is_pid(SPI) andalso is_atom(DeviceName) andalso is_map(Transaction) + is_port(SPI) andalso is_atom(DeviceName) andalso is_map(Transaction) -> port:call(SPI, {write_read, DeviceName, Transaction}). diff --git a/libs/eavmlib/src/uart.erl b/libs/eavmlib/src/uart.erl index 027f82023..0cc47c25d 100644 --- a/libs/eavmlib/src/uart.erl +++ b/libs/eavmlib/src/uart.erl @@ -21,22 +21,27 @@ -module(uart). -export([open/1, open/2, close/1, read/1, write/2]). +-spec open(integer() | list() | binary(), [tuple()]) -> port(). open(Name, Opts) -> open([{peripheral, Name} | Opts]). +-spec open([tuple()]) -> port(). open(Opts) -> open_port({spawn, "uart"}, migrate_config(Opts)). -close(Pid) -> - port:call(Pid, close). +-spec close(Port :: port()) -> ok | {error, any()}. +close(Port) -> + port:call(Port, close). -read(Pid) -> - port:call(Pid, read). +-spec read(Port :: port()) -> {ok, binary()} | {error, any()}. +read(Port) -> + port:call(Port, read). -write(Pid, B) -> +-spec write(Port :: port(), B :: iolist()) -> ok | {error, any()}. +write(Port, B) -> case is_iolist(B) of true -> - port:call(Pid, {write, B}); + port:call(Port, {write, B}); false -> throw(badarg) end. diff --git a/libs/estdlib/src/erlang.erl b/libs/estdlib/src/erlang.erl index 9c88b02cb..13cdbe8bb 100644 --- a/libs/estdlib/src/erlang.erl +++ b/libs/estdlib/src/erlang.erl @@ -160,6 +160,11 @@ | link | monitor. +-type send_destination() :: + pid() + | port() + | atom(). + %%----------------------------------------------------------------------------- %% @param Time time in milliseconds after which to send the timeout message. %% @param Dest Pid or server name to which to send the timeout message. @@ -859,17 +864,16 @@ ref_to_list(_Ref) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- -%% @param Name name of the process to register -%% @param Pid pid of the process to register +%% @param Name name of the process to register +%% @param PidOrPort pid or port of the process to register %% @returns `true' %% @doc Register a name for a given process. -%% Processes can be registered with several names. -%% Unlike Erlang/OTP, ports are not distinguished from processes. -%% Errors with `badarg' if the name is already registered. +%% Errors with `badarg' if the name is already registered or if the process +%% is already registered. %% @end %%----------------------------------------------------------------------------- --spec register(Name :: atom(), Pid :: pid()) -> true. -register(_Name, _Pid) -> +-spec register(Name :: atom(), PidOrPort :: pid() | port()) -> true. +register(_Name, _PidOrPort) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- @@ -890,7 +894,7 @@ unregister(_Name) -> %% @doc Lookup a process by name. %% @end %%----------------------------------------------------------------------------- --spec whereis(Name :: atom()) -> pid() | undefined. +-spec whereis(Name :: atom()) -> pid() | port() | undefined. whereis(_Name) -> erlang:nif_error(undefined). @@ -1002,13 +1006,13 @@ make_ref() -> %% @doc Send a message to a given process %% @end %%----------------------------------------------------------------------------- --spec send(Pid :: pid(), Message :: Message) -> Message. -send(_Pid, _Message) -> +-spec send(Target :: send_destination(), Message :: Message) -> Message. +send(_Target, _Message) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- -%% @param Type type of monitor to create -%% @param Pid pid of the object to monitor +%% @param Type type of monitor to create +%% @param PidOrPort pid or port of the object to monitor %% @returns a monitor reference %% @doc Create a monitor on a process or on a port. %% When the process or the port terminates, the following message is sent to @@ -1019,8 +1023,10 @@ send(_Pid, _Message) -> %% Unlike Erlang/OTP, monitors are only supported for processes and ports. %% @end %%----------------------------------------------------------------------------- --spec monitor(Type :: process | port, Pid :: pid()) -> reference(). -monitor(_Type, _Pid) -> +-spec monitor + (Type :: process, Pid :: pid()) -> reference(); + (Type :: port, Port :: port()) -> reference(). +monitor(_Type, _PidOrPort) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- @@ -1102,7 +1108,7 @@ exit(_Process, _Reason) -> %% Unlike Erlang/OTP, ports are identified by pids. %% @end %%----------------------------------------------------------------------------- --spec open_port(PortName :: {spawn, iodata()}, Options :: [any()] | map()) -> pid(). +-spec open_port(PortName :: {spawn, iodata()}, Options :: [any()] | map()) -> port(). open_port(_PortName, _Options) -> erlang:nif_error(undefined). diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index a8dc3c3d3..1adfebc75 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -39,6 +39,7 @@ #include "smp.h" #include "synclist.h" #include "sys.h" +#include "term.h" #include "utils.h" #include "valueshashtable.h" @@ -56,7 +57,7 @@ struct RegisteredProcess struct ListHead registered_processes_list_head; int atom_index; - int local_process_id; + term local_pid_or_port; }; GlobalContext *globalcontext_new() @@ -509,7 +510,7 @@ void globalcontext_init_process(GlobalContext *glb, Context *ctx) SMP_SPINLOCK_UNLOCK(&glb->processes_spinlock); } -bool globalcontext_register_process(GlobalContext *glb, int atom_index, int local_process_id) +bool globalcontext_register_process(GlobalContext *glb, int atom_index, term local_pid_or_port) { struct ListHead *registered_processes_list = synclist_wrlock(&glb->registered_processes); struct ListHead *item; @@ -527,7 +528,7 @@ bool globalcontext_register_process(GlobalContext *glb, int atom_index, int loca AVM_ABORT(); } registered_process->atom_index = atom_index; - registered_process->local_process_id = local_process_id; + registered_process->local_pid_or_port = local_pid_or_port; list_append(registered_processes_list, ®istered_process->registered_processes_list_head); synclist_unlock(&glb->registered_processes); @@ -561,7 +562,7 @@ void globalcontext_maybe_unregister_process_id(GlobalContext *glb, int target_pr struct ListHead *tmp; MUTABLE_LIST_FOR_EACH (item, tmp, registered_processes_list) { struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head); - if (registered_process->local_process_id == target_process_id) { + if (term_to_local_process_id(registered_process->local_pid_or_port) == target_process_id) { list_remove(item); free(registered_process); } @@ -569,14 +570,14 @@ void globalcontext_maybe_unregister_process_id(GlobalContext *glb, int target_pr synclist_unlock(&glb->registered_processes); } -int globalcontext_get_registered_process(GlobalContext *glb, int atom_index) +term globalcontext_get_registered_process(GlobalContext *glb, int atom_index) { struct ListHead *registered_processes_list = synclist_rdlock(&glb->registered_processes); struct ListHead *item; LIST_FOR_EACH (item, registered_processes_list) { const struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head); if (registered_process->atom_index == atom_index) { - int result = registered_process->local_process_id; + term result = registered_process->local_pid_or_port; synclist_unlock(&glb->registered_processes); return result; } @@ -584,7 +585,7 @@ int globalcontext_get_registered_process(GlobalContext *glb, int atom_index) synclist_unlock(&glb->registered_processes); - return 0; + return UNDEFINED_ATOM; } term globalcontext_get_registered_name_process(GlobalContext *glb, int local_process_id) @@ -594,7 +595,7 @@ term globalcontext_get_registered_name_process(GlobalContext *glb, int local_pro struct ListHead *tmp; MUTABLE_LIST_FOR_EACH (item, tmp, registered_processes_list) { struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head); - if (registered_process->local_process_id == local_process_id) { + if (term_to_local_process_id(registered_process->local_pid_or_port) == local_process_id) { int result = registered_process->atom_index; synclist_unlock(&glb->registered_processes); return term_from_atom_index(result); diff --git a/src/libAtomVM/globalcontext.h b/src/libAtomVM/globalcontext.h index 741992f12..1f06ca53b 100644 --- a/src/libAtomVM/globalcontext.h +++ b/src/libAtomVM/globalcontext.h @@ -340,10 +340,10 @@ void globalcontext_init_process(GlobalContext *glb, Context *ctx); * @details Register a process with a certain name (atom) so it can be easily retrieved later. * @param glb the global context, each registered process will be globally available for that context. * @param atom_index the atom table index. - * @param local_process_id the process local id. + * @param local_pid_or_port the local pid or port * @returns \c true if the process was registered, \c false if another process with the same name already existed */ -bool globalcontext_register_process(GlobalContext *glb, int atom_index, int local_process_id); +bool globalcontext_register_process(GlobalContext *glb, int atom_index, term local_pid_or_port); /** * @brief Get registered name for a process/port @@ -363,9 +363,9 @@ term globalcontext_get_registered_name_process(GlobalContext *glb, int local_pro * @details Returns the local process id of a previously registered process. * @param glb the global context. * @param atom_index the atom table index. - * @returns a previously registered process local id. + * @returns a previously registered process local id or UNDEFINED_ATOM */ -int globalcontext_get_registered_process(GlobalContext *glb, int atom_index); +term globalcontext_get_registered_process(GlobalContext *glb, int atom_index); /** * @brief Unregister a process by name diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index 2537bd131..9e59b3fb6 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -1043,12 +1043,12 @@ static term nif_erlang_register_2(Context *ctx, int argc, term argv[]) // pid must be existing, not already registered, and not the atom undefined. if (UNLIKELY(!globalcontext_process_exists(ctx->global, pid)) || - globalcontext_get_registered_process(ctx->global, atom_index) != 0 || + globalcontext_get_registered_process(ctx->global, atom_index) != UNDEFINED_ATOM || reg_name_term == UNDEFINED_ATOM){ RAISE_ERROR(BADARG_ATOM); } - globalcontext_register_process(ctx->global, atom_index, pid); + globalcontext_register_process(ctx->global, atom_index, pid_or_port_term); return TRUE_ATOM; } @@ -1079,12 +1079,7 @@ static term nif_erlang_whereis_1(Context *ctx, int argc, term argv[]) int atom_index = term_to_atom_index(reg_name_term); - int local_process_id = globalcontext_get_registered_process(ctx->global, atom_index); - if (local_process_id) { - return term_from_local_process_id(local_process_id); - } else { - return UNDEFINED_ATOM; - } + return globalcontext_get_registered_process(ctx->global, atom_index); } static NativeHandlerResult process_echo_mailbox(Context *ctx) @@ -1454,12 +1449,13 @@ static term nif_erlang_send_2(Context *ctx, int argc, term argv[]) UNUSED(dummy); int atom_index = term_to_atom_index(target); - int local_process_id = globalcontext_get_registered_process(glb, atom_index); - if (UNLIKELY(local_process_id == 0)) { + term pid_or_port = globalcontext_get_registered_process(glb, atom_index); + if (UNLIKELY(pid_or_port == UNDEFINED_ATOM)) { synclist_unlock(&glb->processes_table); RAISE_ERROR(BADARG_ATOM); } + int32_t local_process_id = term_to_local_process_id(pid_or_port); Context *p = globalcontext_get_process_nolock(glb, local_process_id); if (IS_NULL_PTR(p)) { synclist_unlock(&glb->processes_table); @@ -4061,12 +4057,13 @@ static term nif_erlang_setnode_2(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - int netkernel_pid = globalcontext_get_registered_process(ctx->global, NET_KERNEL_ATOM_INDEX); - if (UNLIKELY(netkernel_pid == 0)) { + term netkernel_pid = globalcontext_get_registered_process(ctx->global, NET_KERNEL_ATOM_INDEX); + if (UNLIKELY(netkernel_pid == UNDEFINED_ATOM)) { RAISE_ERROR(BADARG_ATOM); } - Context *net_kernel = globalcontext_get_process_lock(ctx->global, netkernel_pid); + int32_t netkernel_local_process_id = term_to_local_process_id(netkernel_pid); + Context *net_kernel = globalcontext_get_process_lock(ctx->global, netkernel_local_process_id); if (IS_NULL_PTR(net_kernel)) { RAISE_ERROR(BADARG_ATOM); } diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index 11d12f23e..35094de4e 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -2407,14 +2407,16 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) if (UNLIKELY(term_is_external_pid(recipient_term))) { dist_send_message(recipient_term, x_regs[1], ctx); } else { + if (term_is_atom(recipient_term)) { + recipient_term = globalcontext_get_registered_process(ctx->global, term_to_atom_index(recipient_term)); + if (UNLIKELY(recipient_term == UNDEFINED_ATOM)) { + RAISE_ERROR(BADARG_ATOM); + } + } + int local_process_id; if (term_is_local_pid_or_port(recipient_term)) { local_process_id = term_to_local_process_id(recipient_term); - } else if (term_is_atom(recipient_term)) { - local_process_id = globalcontext_get_registered_process(ctx->global, term_to_atom_index(recipient_term)); - if (UNLIKELY(local_process_id == 0)) { - RAISE_ERROR(BADARG_ATOM); - } } else { RAISE_ERROR(BADARG_ATOM); } diff --git a/src/platforms/emscripten/src/lib/sys.c b/src/platforms/emscripten/src/lib/sys.c index 5ca6474b0..2eb6cf9ee 100644 --- a/src/platforms/emscripten/src/lib/sys.c +++ b/src/platforms/emscripten/src/lib/sys.c @@ -411,7 +411,11 @@ static int sys_emscripten_get_target(GlobalContext *glb, const char *target_name return -1; } int target_atom_index = term_to_atom_index(target_atom); - return globalcontext_get_registered_process(glb, target_atom_index); + term target_pid = globalcontext_get_registered_process(glb, target_atom_index); + if (!term_is_local_pid_or_port(target_pid)) { + return 0; + } + return term_to_local_process_id(target_pid); } static void sys_emscripten_send_message(GlobalContext *glb, int target_pid, const char *message, struct PromiseResource *promise) diff --git a/src/platforms/esp32/components/avm_builtins/gpio_driver.c b/src/platforms/esp32/components/avm_builtins/gpio_driver.c index ef0279044..ee374f470 100644 --- a/src/platforms/esp32/components/avm_builtins/gpio_driver.c +++ b/src/platforms/esp32/components/avm_builtins/gpio_driver.c @@ -328,7 +328,7 @@ static term gpiodriver_close(Context *ctx) { GlobalContext *glb = ctx->global; int gpio_atom_index = atom_table_ensure_atom(glb->atom_table, gpio_atom, AtomTableNoOpts); - if (UNLIKELY(!globalcontext_get_registered_process(glb, gpio_atom_index))) { + if (UNLIKELY(globalcontext_get_registered_process(glb, gpio_atom_index) == UNDEFINED_ATOM)) { return ERROR_ATOM; } @@ -463,20 +463,19 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) term trigger = term_get_tuple_element(cmd, 2); if (term_get_tuple_arity(cmd) == 4) { term pid = term_get_tuple_element(cmd, 3); - if (UNLIKELY(!term_is_pid(pid) && !term_is_atom(pid))) { + if (UNLIKELY(!term_is_local_pid(pid) && !term_is_atom(pid))) { ESP_LOGE(TAG, "Invalid listener parameter, must be a pid() or registered process!"); return ERROR_ATOM; } - if (term_is_pid(pid)) { + if (term_is_atom(pid)) { + int pid_atom_index = term_to_atom_index(pid); + pid = globalcontext_get_registered_process(ctx->global, pid_atom_index); + } + if (term_is_local_pid(pid)) { target_local_pid = term_to_local_process_id(pid); } else { - int pid_atom_index = term_to_atom_index(pid); - int32_t registered_process = (int32_t) globalcontext_get_registered_process(ctx->global, pid_atom_index); - if (UNLIKELY(registered_process == 0)) { - ESP_LOGE(TAG, "Invalid listener parameter, atom() is not a registered process name!"); - return ERROR_ATOM; - } - target_local_pid = registered_process; + ESP_LOGE(TAG, "Invalid listener parameter, must be a pid() or registered process!"); + return ERROR_ATOM; } } else { target_local_pid = target_pid; diff --git a/src/platforms/esp32/components/avm_builtins/i2c_driver.c b/src/platforms/esp32/components/avm_builtins/i2c_driver.c index 4f53c13a4..febd6d337 100644 --- a/src/platforms/esp32/components/avm_builtins/i2c_driver.c +++ b/src/platforms/esp32/components/avm_builtins/i2c_driver.c @@ -633,8 +633,8 @@ static NativeHandlerResult i2cdriver_consume_mailbox(Context *ctx) I2CAcquireResult i2c_driver_acquire(term i2c_port, i2c_port_t *i2c_num, GlobalContext *global) { - if (UNLIKELY(!term_is_pid(i2c_port))) { - ESP_LOGW(TAG, "acquire: given term is not a PID."); + if (UNLIKELY(!term_is_local_port(i2c_port))) { + ESP_LOGW(TAG, "acquire: given term is not a port."); return I2CAcquireInvalidPeripheral; } @@ -660,8 +660,8 @@ I2CAcquireResult i2c_driver_acquire(term i2c_port, i2c_port_t *i2c_num, GlobalCo void i2c_driver_release(term i2c_port, GlobalContext *global) { - if (UNLIKELY(!term_is_pid(i2c_port))) { - ESP_LOGW(TAG, "release: given term is not a PID."); + if (UNLIKELY(!term_is_local_port(i2c_port))) { + ESP_LOGW(TAG, "release: given term is not a port."); return; } diff --git a/src/platforms/esp32/components/avm_builtins/socket_driver.c b/src/platforms/esp32/components/avm_builtins/socket_driver.c index 6cec74abb..37f0aa45f 100644 --- a/src/platforms/esp32/components/avm_builtins/socket_driver.c +++ b/src/platforms/esp32/components/avm_builtins/socket_driver.c @@ -858,7 +858,7 @@ static void do_connect(Context *ctx, const GenMessage *gen_message) term active_term = interop_proplist_get_value_default(params, ACTIVE_ATOM, TRUE_ATOM); term controlling_process_term = interop_proplist_get_value(params, CONTROLLING_PROCESS_ATOM); - bool ok = term_is_pid(controlling_process_term); + bool ok = term_is_local_pid(controlling_process_term); if (UNLIKELY(!ok)) { do_send_error_reply(ctx, ERR_ARG, ref_ticks, pid); return; @@ -1022,7 +1022,7 @@ void do_udp_open(Context *ctx, const GenMessage *gen_message) term active_term = interop_proplist_get_value_default(params, ACTIVE_ATOM, TRUE_ATOM); term controlling_process_term = interop_proplist_get_value(params, CONTROLLING_PROCESS_ATOM); - bool ok = term_is_pid(controlling_process_term); + bool ok = term_is_local_pid(controlling_process_term); if (UNLIKELY(!ok)) { do_send_error_reply(ctx, ERR_ARG, ref_ticks, pid); return; @@ -1369,7 +1369,7 @@ static void do_controlling_process(Context *ctx, const GenMessage *gen_message) return; } term new_pid_term = term_get_tuple_element(gen_message->req, 1); - if (UNLIKELY(!term_is_pid(new_pid_term))) { + if (UNLIKELY(!term_is_local_pid(new_pid_term))) { do_send_error_reply(ctx, ERR_ARG, ref_ticks, pid); } else { term return_msg; diff --git a/src/platforms/esp32/components/avm_builtins/spi_driver.c b/src/platforms/esp32/components/avm_builtins/spi_driver.c index 45e295288..d315ef144 100644 --- a/src/platforms/esp32/components/avm_builtins/spi_driver.c +++ b/src/platforms/esp32/components/avm_builtins/spi_driver.c @@ -677,7 +677,7 @@ static NativeHandlerResult spidriver_consume_mailbox(Context *ctx) bool spi_driver_get_peripheral(term spi_port, spi_host_device_t *host_dev, GlobalContext *global) { - if (UNLIKELY(!term_is_pid(spi_port))) { + if (UNLIKELY(!term_is_local_port(spi_port))) { ESP_LOGW(TAG, "Given term is not a SPI port driver."); return false; } diff --git a/src/platforms/stm32/src/lib/gpio_driver.c b/src/platforms/stm32/src/lib/gpio_driver.c index 27fcec4b3..aea145d8c 100644 --- a/src/platforms/stm32/src/lib/gpio_driver.c +++ b/src/platforms/stm32/src/lib/gpio_driver.c @@ -572,7 +572,7 @@ static term gpiodriver_close(Context *ctx) GlobalContext *glb = ctx->global; term gpio_atom_term = globalcontext_make_atom(glb, gpio_atom); int gpio_atom_index = term_to_atom_index(gpio_atom_term); - if (UNLIKELY(!globalcontext_get_registered_process(glb, gpio_atom_index))) { + if (UNLIKELY(globalcontext_get_registered_process(glb, gpio_atom_index) == UNDEFINED_ATOM)) { AVM_LOGE(TAG, "No active GPIO driver can be found."); return error_tuple_maybe_gc(ctx, NOPROC_ATOM); } @@ -814,16 +814,15 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) AVM_LOGE(TAG, "Invalid listener parameter, must be a pid() or registered process!"); return create_pair(ctx, ERROR_ATOM, globalcontext_make_atom(ctx->global, invalid_listener_atom)); } - if (term_is_pid(pid)) { + if (term_is_atom(pid)) { + int pid_atom_index = term_to_atom_index(pid); + pid = globalcontext_get_registered_process(ctx->global, pid_atom_index); + } + if (term_is_local_pid(pid)) { target_local_pid = term_to_local_process_id(pid); } else { - int pid_atom_index = term_to_atom_index(pid); - int32_t registered_process = (int32_t) globalcontext_get_registered_process(ctx->global, pid_atom_index); - if (UNLIKELY(registered_process == 0)) { - AVM_LOGE(TAG, "Invalid listener parameter, atom() is not a registered process name!"); - return create_pair(ctx, ERROR_ATOM, NOPROC_ATOM); - } - target_local_pid = registered_process; + AVM_LOGE(TAG, "Invalid listener parameter, must be a pid() or registered process!"); + return create_pair(ctx, ERROR_ATOM, NOPROC_ATOM); } } else { target_local_pid = target_pid; diff --git a/tests/erlang_tests/test_regecho_driver.erl b/tests/erlang_tests/test_regecho_driver.erl index 985ef63a4..685f7e3ee 100644 --- a/tests/erlang_tests/test_regecho_driver.erl +++ b/tests/erlang_tests/test_regecho_driver.erl @@ -23,7 +23,10 @@ -export([start/0, do_open_port/2, echo/1]). start() -> - register(echo, do_open_port("echo", [])), + Port = do_open_port("echo", []), + true = is_port(Port), + register(echo, Port), + true = is_port(whereis(echo)), length(echo("Hello World")). do_open_port(PortName, Param) ->