Skip to content

Commit

Permalink
Allow sending message to registered process name
Browse files Browse the repository at this point in the history
Changes `erlang:send/2` to accept a pid or registered process name. Updates
`tests/erlang_tests/test_send_nif_and_echo.erl` to also test sending directly to the registered
name, and `tests/erlang_tests/test_send.erl` to test sending to an an unregistered `atom` name.

Fixes issue atomvm#98

Signed-off-by: Winford <winford@object.stream>
  • Loading branch information
UncleGrumpy committed Jun 13, 2023
1 parent fb9eb9e commit a7186e9
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bug in when putting integers in bit syntax with integer field sizes
- Fixed numerous bugs in memory allocations that could crash the VM
- Fixed SNTP support that had been broken in IDF 4.x builds
- Fixed `erlang:send/2` not sending to registered name

### Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion src/libAtomVM/globalcontext.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb)
free(glb);
}

static Context *globalcontext_get_process_nolock(GlobalContext *glb, int32_t process_id)
Context *globalcontext_get_process_nolock(GlobalContext *glb, int32_t process_id)
{
struct ListHead *item;
Context *p = NULL;
Expand Down
13 changes: 13 additions & 0 deletions src/libAtomVM/globalcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@ GlobalContext *globalcontext_new();
*/
void globalcontext_destroy(GlobalContext *glb);

/**
* @brief Gets a Context from the process table, acquiring a lock on the process
* table.
*
* @details Retrieves from the process table the context with the given local
* process id. If the process can be found, without locking the process table.
* This is unsafe unless a lock on the process table has been obtained previously.
* @param glb the global context (that owns the process table).
* @param process_id the local process id.
* @returns a Context * with the requested local process id or NULL if not found.
*/
Context *globalcontext_get_process_nolock(GlobalContext *glb, int32_t process_id);

/**
* @brief Gets a Context from the process table, acquiring a lock on the process
* table.
Expand Down
36 changes: 32 additions & 4 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1284,12 +1284,40 @@ static term nif_erlang_spawn(Context *ctx, int argc, term argv[])
static term nif_erlang_send_2(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
term dest = argv[0];
GlobalContext *glb = ctx->global;
struct ListHead *processes_table_list = synclist_rdlock(&glb->processes_table);

Context *p = NULL;
struct ListHead *item;
if (term_is_pid(dest)) {
int32_t dest_pid = term_to_local_process_id(dest);

globalcontext_send_message_nolock(glb, dest_pid, argv[1]);
synclist_unlock(&glb->processes_table);

term pid_term = argv[0];
VALIDATE_VALUE(pid_term, term_is_pid);
} else if (term_is_atom(dest)) {
int atom_index = term_to_atom_index(dest);

int test_pid = globalcontext_get_registered_process(glb, atom_index);
if (UNLIKELY(test_pid == 0)) {
synclist_unlock(&glb->processes_table);
RAISE_ERROR(BADARG_ATOM);
}

int local_process_id = term_to_local_process_id(pid_term);
globalcontext_send_message(ctx->global, local_process_id, argv[1]);
p = globalcontext_get_process_nolock(glb, test_pid);
if (UNLIKELY(IS_NULL_PTR(p))) {
synclist_unlock(&glb->processes_table);
RAISE_ERROR(BADARG_ATOM);
} else {
int32_t dest_pid = p->process_id;
globalcontext_send_message_nolock(glb, dest_pid, argv[1]);
synclist_unlock(&glb->processes_table);
}
} else {
synclist_unlock(&glb->processes_table);
RAISE_ERROR(BADARG_ATOM);
}

return argv[1];
}
Expand Down
59 changes: 54 additions & 5 deletions tests/erlang_tests/test_send.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,64 @@

-module(test_send).

-export([start/0, send2/2]).
-export([start/0]).

start() ->
send2(5, 1) + send2(self(), -1).
Dead = spawn(fun() -> ok end),
Sent = send(self(), 32),
receive
Any ->
Recv = Any
end,
Sent - Recv + send_mal(5, 3) + send_bad_atom(bogus, 4) + send_dead(Dead, 6) +
send_registered(8).

send2(A, B) ->
send(A, B) ->
try erlang:send(A, B) of
B -> -1;
Any -> Any
B -> B;
_Any -> -1
catch
error:badarg -> B - 2;
_:_ -> -4
end.

send_mal(A, B) ->
try erlang:send(A, B) of
B -> B;
_Any -> -1
catch
error:badarg -> B - 3;
_:_ -> -4
end.

send_bad_atom(A, B) ->
try erlang:send(A, B) of
B -> B;
_Any -> -1
catch
error:badarg -> B - 4;
_:_ -> -4
end.

send_dead(A, B) ->
try erlang:send(A, B) of
B -> B - 6;
_Any -> -1
catch
error:badarg -> -2;
_:_ -> -4
end.

send_registered(B) ->
erlang:register(listen, self()),
try erlang:send(listen, B) of
B ->
receive
B -> B - 8;
_Any -> -1
end;
_Any ->
-1
catch
error:badarg -> -2;
_:_ -> -4
Expand Down
11 changes: 9 additions & 2 deletions tests/erlang_tests/test_send_nif_and_echo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,20 @@

start() ->
register(echo, do_open_port(<<"echo">>, [])),
byte_size(echo(<<"Hello World">>)).
byte_size(echo(<<"Hello World">>)) + byte_size(to_pid(erlang:whereis(echo), <<"Hello World">>)).

do_open_port(PortName, Param) ->
open_port({spawn, PortName}, Param).

echo(SendValue) ->
erlang:send(whereis(echo), {self(), SendValue}),
erlang:send(echo, {self(), SendValue}),
receive
Value ->
Value
end.

to_pid(Pid, SendValue) ->
erlang:send(Pid, {self(), SendValue}),
receive
Value ->
Value
Expand Down
4 changes: 2 additions & 2 deletions tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ struct Test tests[] = {
TEST_CASE_EXPECTED(long_atoms, 4),
TEST_CASE_EXPECTED(test_concat_badarg, 4),
TEST_CASE_EXPECTED(register_and_whereis_badarg, 333),
TEST_CASE_EXPECTED(test_send, -3),
TEST_CASE(test_send),
TEST_CASE_EXPECTED(test_open_port_badargs, -21),
TEST_CASE_EXPECTED(prime_ext, 1999),
TEST_CASE_EXPECTED(test_try_case_end, 256),
Expand Down Expand Up @@ -477,7 +477,7 @@ struct Test tests[] = {
TEST_CASE_ATOMVM_ONLY(test_close_console_driver, 0),
TEST_CASE_ATOMVM_ONLY(test_close_echo_driver, 0),
TEST_CASE_ATOMVM_ONLY(test_regecho_driver, 11),
TEST_CASE_ATOMVM_ONLY(test_send_nif_and_echo, 11),
TEST_CASE_ATOMVM_ONLY(test_send_nif_and_echo, 22),

TEST_CASE_EXPECTED(test_code_load_binary, 24),
TEST_CASE_EXPECTED(test_code_load_abs, 24),
Expand Down

0 comments on commit a7186e9

Please sign in to comment.