Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added `erlang:node/1` BIF
- Added `erts_internal:cmp_term/2`
- Added support for `process_info/1` and `process_info/2` with list argument

### Changed

Expand Down
2 changes: 1 addition & 1 deletion doc/src/apidocs/libatomvm/data_structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Data Structures
:allow-dot-graphs:
.. doxygenstruct:: AVMPackData
:allow-dot-graphs:
.. doxygenstruct:: BuiltInAtomRequestSignal
.. doxygenstruct:: ProcessInfoRequestSignal
:allow-dot-graphs:
.. doxygenstruct:: BuiltInAtomSignal
:allow-dot-graphs:
Expand Down
113 changes: 87 additions & 26 deletions src/libAtomVM/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ void context_destroy(Context *ctx)
while (signal_message) {
switch (signal_message->type) {
case ProcessInfoRequestSignal: {
struct BuiltInAtomRequestSignal *request_signal
= CONTAINER_OF(signal_message, struct BuiltInAtomRequestSignal, base);
struct ProcessInfoRequestSignal *request_signal
= CONTAINER_OF(signal_message, struct ProcessInfoRequestSignal, base);
context_process_process_info_request_signal(ctx, request_signal, true);
break;
}
Expand Down Expand Up @@ -312,36 +312,93 @@ void context_process_kill_signal(Context *ctx, struct TermSignal *signal)
context_update_flags(ctx, ~NoFlags, Killed);
}

void context_process_process_info_request_signal(Context *ctx, struct BuiltInAtomRequestSignal *signal, bool process_table_locked)
void context_process_process_info_request_signal(Context *ctx, struct ProcessInfoRequestSignal *signal, bool process_table_locked)
{
Context *target;
if (process_table_locked) {
target = globalcontext_get_process_nolock(ctx->global, signal->sender_pid);
} else {
target = globalcontext_get_process_lock(ctx->global, signal->sender_pid);
}
if (LIKELY(target)) {

if (UNLIKELY(!target)) {
return;
}

if (signal->mode == PROCESS_INFO_SINGLE) {
term atom = signal->atoms[0];
size_t term_size;
if (context_get_process_info(ctx, NULL, &term_size, signal->atom, NULL)) {
Heap heap;
if (UNLIKELY(memory_init_heap(&heap, term_size) != MEMORY_GC_OK)) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
} else {
term ret;
if (context_get_process_info(ctx, &ret, NULL, signal->atom, &heap)) {
mailbox_send_term_signal(target, TrapAnswerSignal, ret);
} else {
mailbox_send_immediate_signal(target, TrapExceptionSignal, ret);
}
memory_destroy_heap(&heap, ctx->global);
if (!context_get_process_info(ctx, NULL, &term_size, atom, NULL)) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
goto done;
}

Heap heap;
if (UNLIKELY(memory_init_heap(&heap, term_size) != MEMORY_GC_OK)) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
goto done;
}

term ret;
if (context_get_process_info(ctx, &ret, NULL, atom, &heap)) {
// return [] when unregistered (BEAM backward compatibility)
if (atom == REGISTERED_NAME_ATOM && term_is_tuple(ret) && term_is_nil(term_get_tuple_element(ret, 1))) {
ret = term_nil();
}
mailbox_send_term_signal(target, TrapAnswerSignal, ret);
} else {
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
mailbox_send_immediate_signal(target, TrapExceptionSignal, ret);
}
memory_destroy_heap(&heap, ctx->global);
} else {
size_t total_size = 0;
for (size_t i = 0; i < signal->len; i++) {
size_t item_size;
if (UNLIKELY(!context_get_process_info(ctx, NULL, &item_size, signal->atoms[i], NULL))) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
goto done;
}
total_size += item_size + CONS_SIZE;
}

if (signal->len == 0) {
mailbox_send_term_signal(target, TrapAnswerSignal, term_nil());
goto done;
}
if (!process_table_locked) {
globalcontext_get_process_unlock(ctx->global, target);

Heap heap;
if (UNLIKELY(memory_init_heap(&heap, total_size) != MEMORY_GC_OK)) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
goto done;
}

// Build list backwards to preserve input order
term result = term_nil();
bool build_ok = true;
for (ssize_t i = (ssize_t) signal->len - 1; i >= 0; i--) {
term item_result;
if (UNLIKELY(!context_get_process_info(ctx, &item_result, NULL, signal->atoms[i], &heap))) {
mailbox_send_immediate_signal(target, TrapExceptionSignal, item_result);
build_ok = false;
break;
}

if (signal->mode == PROCESS_INFO_LIST_OMIT_UNREGISTERED && signal->atoms[i] == REGISTERED_NAME_ATOM && term_is_nil(term_get_tuple_element(item_result, 1))) {
continue;
}

result = term_list_prepend(item_result, result, &heap);
}
} // else: sender died
if (LIKELY(build_ok)) {
mailbox_send_term_signal(target, TrapAnswerSignal, result);
}
memory_destroy_heap(&heap, ctx->global);
}

done:
if (!process_table_locked) {
globalcontext_get_process_unlock(ctx->global, target);
}
}

bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal)
Expand Down Expand Up @@ -525,6 +582,7 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
case MESSAGE_QUEUE_LEN_ATOM:
case REGISTERED_NAME_ATOM:
case MEMORY_ATOM:
case TRAP_EXIT_ATOM:
ret_size = TUPLE_SIZE(2);
break;
case LINKS_ATOM: {
Expand Down Expand Up @@ -589,12 +647,8 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
// registered_name for process or port..
case REGISTERED_NAME_ATOM: {
term name = globalcontext_get_registered_name_process(ctx->global, ctx->process_id);
if (term_is_invalid_term((name))) {
ret = term_nil(); // Set ret to an empty list to match erlang behaviour
} else {
term_put_tuple_element(ret, 0, REGISTERED_NAME_ATOM);
term_put_tuple_element(ret, 1, name);
}
term_put_tuple_element(ret, 0, REGISTERED_NAME_ATOM);
term_put_tuple_element(ret, 1, term_is_invalid_term(name) ? term_nil() : name);
break;
}

Expand Down Expand Up @@ -630,6 +684,13 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
break;
}

// true if a process traps exits, otherwise false
case TRAP_EXIT_ATOM: {
term_put_tuple_element(ret, 0, TRAP_EXIT_ATOM);
term_put_tuple_element(ret, 1, ctx->trap_exit ? TRUE_ATOM : FALSE_ATOM);
break;
}

// pids of linked processes
case LINKS_ATOM: {
term_put_tuple_element(ret, 0, LINKS_ATOM);
Expand Down
4 changes: 2 additions & 2 deletions src/libAtomVM/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,10 @@ void context_process_kill_signal(Context *ctx, struct TermSignal *signal);
* @brief Process a process info request signal.
*
* @param ctx the context being executed
* @param signal the process info signal
* @param signal the process info request signal
* @param process_table_locked whether process table is already locked
*/
void context_process_process_info_request_signal(Context *ctx, struct BuiltInAtomRequestSignal *signal, bool process_table_locked);
void context_process_process_info_request_signal(Context *ctx, struct ProcessInfoRequestSignal *signal, bool process_table_locked);

/**
* @brief Process a trap answer signal.
Expand Down
4 changes: 2 additions & 2 deletions src/libAtomVM/jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,8 @@ static Context *jit_process_signal_messages(Context *ctx, JITState *jit_state)
break;
}
case ProcessInfoRequestSignal: {
struct BuiltInAtomRequestSignal *request_signal
= CONTAINER_OF(signal_message, struct BuiltInAtomRequestSignal, base);
struct ProcessInfoRequestSignal *request_signal
= CONTAINER_OF(signal_message, struct ProcessInfoRequestSignal, base);
context_process_process_info_request_signal(ctx, request_signal, false);
break;
}
Expand Down
25 changes: 15 additions & 10 deletions src/libAtomVM/mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@
break;
}
case ProcessInfoRequestSignal: {
struct BuiltInAtomRequestSignal *request_signal
= CONTAINER_OF(m, struct BuiltInAtomRequestSignal, base);
struct ProcessInfoRequestSignal *request_signal
= CONTAINER_OF(m, struct ProcessInfoRequestSignal, base);
free(request_signal);
break;
}
Expand Down Expand Up @@ -217,7 +217,7 @@
MailboxMessage *current_first = NULL;
do {
m->next = current_first;
} while (!ATOMIC_COMPARE_EXCHANGE_WEAK_PTR(&c->mailbox.outer_first, &current_first, m));

Check failure on line 220 in src/libAtomVM/mailbox.c

View workflow job for this annotation

GitHub Actions / pico (pico)

note: in expansion of macro 'ATOMIC_COMPARE_EXCHANGE_WEAK_PTR'
}

void mailbox_post_message(Context *c, MailboxMessage *m)
Expand Down Expand Up @@ -291,19 +291,24 @@
mailbox_post_message(c, &immediate_signal->base);
}

void mailbox_send_built_in_atom_request_signal(
Context *c, enum MessageType type, int32_t pid, term atom)
void mailbox_send_process_info_request_signal(
Context *c, int32_t sender_pid, process_info_mode_t mode, const term *atoms, size_t len)
{
struct BuiltInAtomRequestSignal *atom_request = malloc(sizeof(struct BuiltInAtomRequestSignal));
if (IS_NULL_PTR(atom_request)) {
struct ProcessInfoRequestSignal *signal = malloc(
sizeof(struct ProcessInfoRequestSignal) + len * sizeof(term));
if (IS_NULL_PTR(signal)) {
fprintf(stderr, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
return;
}
atom_request->base.type = type;
atom_request->sender_pid = pid;
atom_request->atom = atom;
signal->base.type = ProcessInfoRequestSignal;
signal->sender_pid = sender_pid;
signal->mode = mode;
signal->len = len;
for (size_t i = 0; i < len; i++) {
signal->atoms[i] = atoms[i];
}

mailbox_post_message(c, &atom_request->base);
mailbox_post_message(c, &signal->base);
}

void mailbox_send_ref_signal(Context *c, enum MessageType type, uint64_t ref_ticks)
Expand Down
24 changes: 17 additions & 7 deletions src/libAtomVM/mailbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,21 @@ struct ImmediateSignal
term immediate;
};

struct BuiltInAtomRequestSignal
typedef enum
{
PROCESS_INFO_SINGLE,
PROCESS_INFO_LIST,
PROCESS_INFO_LIST_OMIT_UNREGISTERED,
} process_info_mode_t;

struct ProcessInfoRequestSignal
{
MailboxMessage base;

int32_t sender_pid;
term atom;
process_info_mode_t mode;
size_t len;
term atoms[];
};

struct RefSignal
Expand Down Expand Up @@ -248,15 +257,16 @@ void mailbox_send_term_signal(Context *c, enum MessageType type, term t);
void mailbox_send_immediate_signal(Context *c, enum MessageType type, term immediate);

/**
* @brief Sends a built-in atom-based request signal to a certain mailbox.
* @brief Sends a process info request signal to a certain mailbox.
*
* @param c the process context.
* @param type the type of the signal
* @param sender_pid the sender of the signal (to get the answer)
* @param atom the built-in atom
* @param mode controls result shape and registered_name handling
* @param atoms array of atom terms to query
* @param len number of atoms in the array
*/
void mailbox_send_built_in_atom_request_signal(
Context *c, enum MessageType type, int32_t sender_pid, term atom);
void mailbox_send_process_info_request_signal(
Context *c, int32_t sender_pid, process_info_mode_t mode, const term *atoms, size_t len);

/**
* @brief Sends a ref signal to a certain mailbox.
Expand Down
Loading
Loading