Skip to content

Commit

Permalink
Add support for encoded local pids in external terms
Browse files Browse the repository at this point in the history
Also add partial support for external pids.

Signed-off-by: Paul Guyot <[email protected]>
  • Loading branch information
pguyot committed Nov 3, 2024
1 parent 24084c5 commit 1ab1736
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 56 deletions.
4 changes: 4 additions & 0 deletions src/libAtomVM/defaultatoms.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ static const char *const unicode_atom = "\x7" "unicode";

static const char *const global_atom = "\x6" "global";

static const char *const nonode_at_nohost_atom = "\xD" "nonode@nohost";

void defaultatoms_init(GlobalContext *glb)
{
int ok = 1;
Expand Down Expand Up @@ -308,6 +310,8 @@ void defaultatoms_init(GlobalContext *glb)

ok &= globalcontext_insert_atom(glb, global_atom) == GLOBAL_ATOM_INDEX;

ok &= globalcontext_insert_atom(glb, nonode_at_nohost_atom) == NONODE_AT_NOHOST_ATOM_INDEX;

if (!ok) {
AVM_ABORT();
}
Expand Down
6 changes: 5 additions & 1 deletion src/libAtomVM/defaultatoms.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ extern "C" {

#define GLOBAL_ATOM_INDEX 111

#define PLATFORM_ATOMS_BASE_INDEX 112
#define NONODE_AT_NOHOST_ATOM_INDEX 112

#define PLATFORM_ATOMS_BASE_INDEX 113

#define FALSE_ATOM TERM_FROM_ATOM_INDEX(FALSE_ATOM_INDEX)
#define TRUE_ATOM TERM_FROM_ATOM_INDEX(TRUE_ATOM_INDEX)
Expand Down Expand Up @@ -317,6 +319,8 @@ extern "C" {

#define GLOBAL_ATOM TERM_FROM_ATOM_INDEX(GLOBAL_ATOM_INDEX)

#define NONODE_AT_NOHOST_ATOM TERM_FROM_ATOM_INDEX(NONODE_AT_NOHOST_ATOM_INDEX)

void defaultatoms_init(GlobalContext *glb);

void platform_defaultatoms_init(GlobalContext *glb);
Expand Down
2 changes: 1 addition & 1 deletion src/libAtomVM/ets_hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ static uint32_t hash_term_incr(term t, int32_t h, GlobalContext *global)
return hash_integer(t, h, global);
} else if (term_is_float(t)) {
return hash_float(t, h, global);
} else if (term_is_pid(t)) {
} else if (term_is_local_pid(t)) {
return hash_pid(t, h, global);
} else if (term_is_reference(t)) {
return hash_reference(t, h, global);
Expand Down
52 changes: 52 additions & 0 deletions src/libAtomVM/externalterm.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@
#include <stdlib.h>

#include "bitstring.h"
#include "defaultatoms.h"
#include "term.h"
#include "unicode.h"
#include "utils.h"

#define NEW_FLOAT_EXT 70
#define NEW_PID_EXT 88
#define SMALL_INTEGER_EXT 97
#define INTEGER_EXT 98
#define ATOM_EXT 100
#define PID_EXT 103
#define SMALL_TUPLE_EXT 104
#define LARGE_TUPLE_EXT 105
#define NIL_EXT 106
Expand Down Expand Up @@ -390,6 +394,18 @@ static int serialize_term(uint8_t *buf, term t, GlobalContext *glb)
k += serialize_term(IS_NULL_PTR(buf) ? NULL : buf + k, mfa, glb);
}
return k;
} else if (term_is_local_pid(t)) {
if (!IS_NULL_PTR(buf)) {
buf[0] = NEW_PID_EXT;
}
size_t k = 1;
k += serialize_term(IS_NULL_PTR(buf) ? NULL : buf + k, NONODE_AT_NOHOST_ATOM, glb);
if (!IS_NULL_PTR(buf)) {
WRITE_32_UNALIGNED(buf + k, term_to_local_process_id(t));
WRITE_32_UNALIGNED(buf + k + 4, 0); // serial
WRITE_32_UNALIGNED(buf + k + 8, 0); // creation
}
return k + 12;
} else {
fprintf(stderr, "Unknown external term type: %" TERM_U_FMT "\n", t);
AVM_ABORT();
Expand Down Expand Up @@ -659,6 +675,26 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm
return term_from_atom_index(global_atom_id);
}

case NEW_PID_EXT: {
size_t node_size;
term node = parse_external_terms(external_term_buf + 1, &node_size, copy, heap, glb);
if (UNLIKELY(!term_is_atom(node))) {
return node;
}
uint32_t number = READ_32_UNALIGNED(external_term_buf + node_size + 1);
uint32_t serial = READ_32_UNALIGNED(external_term_buf + node_size + 5);
uint32_t creation = READ_32_UNALIGNED(external_term_buf + node_size + 9);
// We only support local pids for now.
if (UNLIKELY(node != NONODE_AT_NOHOST_ATOM)) {
return term_invalid_term();
} else {
if (UNLIKELY(serial != 0 || creation != 0)) {
return term_invalid_term();
}
return term_from_local_process_id(number);
}
}

default:
return term_invalid_term();
}
Expand Down Expand Up @@ -948,6 +984,22 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini
return 0;
}

case NEW_PID_EXT: {
if (UNLIKELY(remaining < 1)) {
return INVALID_TERM_SIZE;
}
remaining -= 1;
int buf_pos = 1;
size_t node_size = 0;
int u = calculate_heap_usage(external_term_buf + buf_pos, remaining, &node_size, copy);
if (UNLIKELY(u == INVALID_TERM_SIZE)) {
return INVALID_TERM_SIZE;
}
buf_pos += node_size;
*eterm_size = buf_pos;
return 1 + u;
}

default:
return INVALID_TERM_SIZE;
}
Expand Down
6 changes: 3 additions & 3 deletions src/libAtomVM/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ unsigned long memory_estimate_usage(term t)
} else if (term_is_nil(t)) {
t = temp_stack_pop(&temp_stack);

} else if (term_is_pid(t)) {
} else if (term_is_local_pid(t)) {
t = temp_stack_pop(&temp_stack);

} else if (term_is_nonempty_list(t)) {
Expand Down Expand Up @@ -587,7 +587,7 @@ static void memory_scan_and_copy(HeapFragment *old_fragment, term *mem_start, co
TRACE("Found NIL (%" TERM_X_FMT ")\n", t);
ptr++;

} else if (term_is_pid(t)) {
} else if (term_is_local_pid(t)) {
TRACE("Found PID (%" TERM_X_FMT ")\n", t);
ptr++;

Expand Down Expand Up @@ -810,7 +810,7 @@ HOT_FUNC static term memory_shallow_copy_term(HeapFragment *old_fragment, term t
} else if (term_is_nil(t)) {
return t;

} else if (term_is_pid(t)) {
} else if (term_is_local_pid(t)) {
return t;

} else if (term_is_cp(t)) {
Expand Down
28 changes: 14 additions & 14 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ static term nif_erlang_register_2(Context *ctx, int argc, term argv[])
term reg_name_term = argv[0];
VALIDATE_VALUE(reg_name_term, term_is_atom);
term pid_or_port_term = argv[1];
VALIDATE_VALUE(pid_or_port_term, term_is_pid);
VALIDATE_VALUE(pid_or_port_term, term_is_local_pid);

int atom_index = term_to_atom_index(reg_name_term);
int32_t pid = term_to_local_process_id(pid_or_port_term);
Expand Down Expand Up @@ -1392,7 +1392,7 @@ static term nif_erlang_send_2(Context *ctx, int argc, term argv[])
term target = argv[0];
GlobalContext *glb = ctx->global;

if (term_is_pid(target)) {
if (term_is_local_pid(target)) {
int32_t local_process_id = term_to_local_process_id(target);

globalcontext_send_message(glb, local_process_id, argv[1]);
Expand Down Expand Up @@ -2733,7 +2733,7 @@ static term nif_erlang_process_flag(Context *ctx, int argc, term argv[])
flag = argv[1];
value = argv[2];

VALIDATE_VALUE(pid, term_is_pid);
VALIDATE_VALUE(pid, term_is_local_pid);
int local_process_id = term_to_local_process_id(pid);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
if (IS_NULL_PTR(target)) {
Expand Down Expand Up @@ -3183,7 +3183,7 @@ static term nif_binary_split(Context *ctx, int argc, term argv[])

if (num_segments == 1) {
// not found
if (UNLIKELY(memory_ensure_free_with_roots(ctx, 2, 1, argv, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
if (UNLIKELY(memory_ensure_free_with_roots(ctx, LIST_SIZE(1, 0), 1, argv, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}

Expand Down Expand Up @@ -3434,10 +3434,10 @@ static term nif_erlang_pid_to_list(Context *ctx, int argc, term argv[])
UNUSED(argc);

term t = argv[0];
VALIDATE_VALUE(t, term_is_pid);
VALIDATE_VALUE(t, term_is_local_pid);

char buf[PID_AS_CSTRING_LEN];
int str_len = term_snprint(buf, PID_AS_CSTRING_LEN, t, ctx->global);
char buf[LOCAL_PID_AS_CSTRING_LEN];
int str_len = term_snprint(buf, LOCAL_PID_AS_CSTRING_LEN, t, ctx->global);
if (UNLIKELY(str_len < 0)) {
// TODO: change to internal error or something like that
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
Expand Down Expand Up @@ -3551,7 +3551,7 @@ static term nif_erlang_garbage_collect(Context *ctx, int argc, term argv[])
} else {
// argc == 1
term t = argv[0];
VALIDATE_VALUE(t, term_is_pid);
VALIDATE_VALUE(t, term_is_local_pid);

int local_id = term_to_local_process_id(t);
Context *target = globalcontext_get_process_lock(ctx->global, local_id);
Expand Down Expand Up @@ -3594,7 +3594,7 @@ static term nif_erlang_exit(Context *ctx, int argc, term argv[])
RAISE(LOWERCASE_EXIT_ATOM, reason);
} else {
term target_process = argv[0];
VALIDATE_VALUE(target_process, term_is_pid);
VALIDATE_VALUE(target_process, term_is_local_pid);
term reason = argv[1];
GlobalContext *glb = ctx->global;
Context *target = globalcontext_get_process_lock(glb, term_to_local_process_id(target_process));
Expand Down Expand Up @@ -3707,7 +3707,7 @@ static term nif_erlang_monitor(Context *ctx, int argc, term argv[])
RAISE_ERROR(BADARG_ATOM);
}

VALIDATE_VALUE(target_pid, term_is_pid);
VALIDATE_VALUE(target_pid, term_is_local_pid);

int local_process_id = term_to_local_process_id(target_pid);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
Expand Down Expand Up @@ -3775,7 +3775,7 @@ static term nif_erlang_link(Context *ctx, int argc, term argv[])

term target_pid = argv[0];

VALIDATE_VALUE(target_pid, term_is_pid);
VALIDATE_VALUE(target_pid, term_is_local_pid);

int local_process_id = term_to_local_process_id(target_pid);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
Expand Down Expand Up @@ -3806,7 +3806,7 @@ static term nif_erlang_unlink(Context *ctx, int argc, term argv[])

term target_pid = argv[0];

VALIDATE_VALUE(target_pid, term_is_pid);
VALIDATE_VALUE(target_pid, term_is_local_pid);

int local_process_id = term_to_local_process_id(target_pid);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
Expand Down Expand Up @@ -3837,8 +3837,8 @@ static term nif_erlang_group_leader(Context *ctx, int argc, term argv[])
} else {
term leader = argv[0];
term pid = argv[1];
VALIDATE_VALUE(pid, term_is_pid);
VALIDATE_VALUE(leader, term_is_pid);
VALIDATE_VALUE(pid, term_is_local_pid);
VALIDATE_VALUE(leader, term_is_local_pid);

int local_process_id = term_to_local_process_id(pid);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
Expand Down
6 changes: 3 additions & 3 deletions src/libAtomVM/opcodesswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -2384,7 +2384,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
#ifdef IMPL_EXECUTE_LOOP
term recipient_term = x_regs[0];
int local_process_id;
if (term_is_pid(recipient_term)) {
if (term_is_local_pid(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));
Expand Down Expand Up @@ -2940,7 +2940,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
#ifdef IMPL_EXECUTE_LOOP
TRACE("is_pid/2, label=%i, arg1=%lx\n", label, arg1);

if (!term_is_pid(arg1)) {
if (!term_is_local_pid(arg1)) {
pc = mod->labels[label];
}
#endif
Expand Down Expand Up @@ -2984,7 +2984,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
#ifdef IMPL_EXECUTE_LOOP
TRACE("is_port/2, label=%i, arg1=%lx\n", label, arg1);

if (term_is_pid(arg1)) {
if (term_is_local_pid(arg1)) {
int local_process_id = term_to_local_process_id(arg1);
Context *target = globalcontext_get_process_lock(ctx->global, local_process_id);
bool is_port_driver = false;
Expand Down
2 changes: 1 addition & 1 deletion src/libAtomVM/posix_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ static term nif_atomvm_posix_write(Context *ctx, int argc, term argv[])
static term nif_atomvm_posix_select(Context *ctx, term argv[], enum ErlNifSelectFlags mode)
{
term process_pid_term = argv[1];
VALIDATE_VALUE(process_pid_term, term_is_pid);
VALIDATE_VALUE(process_pid_term, term_is_local_pid);
int32_t process_pid = term_to_local_process_id(process_pid_term);
term select_ref_term = argv[2];
if (select_ref_term != UNDEFINED_ATOM) {
Expand Down
4 changes: 2 additions & 2 deletions src/libAtomVM/term.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ int term_funprint(PrinterFun *fun, term t, const GlobalContext *global)
ret += printed;
return ret;
}
} else if (term_is_pid(t)) {
} else if (term_is_local_pid(t)) {
int32_t process_id = term_to_local_process_id(t);
return fun->print(fun, "<0.%" PRIu32 ".0>", process_id);

Expand Down Expand Up @@ -665,7 +665,7 @@ TermCompareResult term_compare(term t, term other, TermCompareOpts opts, GlobalC
break;

} else if (term_is_pid(t) && term_is_pid(other)) {
//TODO: handle ports
//TODO: handle ports & external pids
result = (t > other) ? TermGreaterThan : TermLessThan;
break;

Expand Down
Loading

0 comments on commit 1ab1736

Please sign in to comment.