Skip to content

Commit da6a4f1

Browse files
committed
Add support for process_info/1 and process_info/2 with list argument
Signed-off-by: Mateusz Furga <mateusz.furga@swmansion.com>
1 parent 006aa37 commit da6a4f1

12 files changed

Lines changed: 517 additions & 134 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ encoding/decoding options, also Elixir `(url_)encode64`/`(url_)decode64` have be
106106
`atomvm:posix_pwrite/3`, `atomvm:posix_fsync/1`, `atomvm:posix_ftruncate/2`,
107107
`atomvm:posix_rename/2`, `atomvm:posix_stat/1`, `atomvm:posix_fstat/1`
108108
- Added POSIX directory functions: `atomvm:posix_mkdir/1`, `atomvm:posix_rmdir/1`,
109+
- Added support for `process_info/1` and `process_info/2` with list argument
109110

110111
### Changed
111112

doc/src/apidocs/libatomvm/data_structures.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Data Structures
2323
:allow-dot-graphs:
2424
.. doxygenstruct:: AVMPackData
2525
:allow-dot-graphs:
26-
.. doxygenstruct:: BuiltInAtomRequestSignal
26+
.. doxygenstruct:: ProcessInfoRequestSignal
2727
:allow-dot-graphs:
2828
.. doxygenstruct:: BuiltInAtomSignal
2929
:allow-dot-graphs:

src/libAtomVM/context.c

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ void context_destroy(Context *ctx)
156156
while (signal_message) {
157157
switch (signal_message->type) {
158158
case ProcessInfoRequestSignal: {
159-
struct BuiltInAtomRequestSignal *request_signal
160-
= CONTAINER_OF(signal_message, struct BuiltInAtomRequestSignal, base);
159+
struct ProcessInfoRequestSignal *request_signal
160+
= CONTAINER_OF(signal_message, struct ProcessInfoRequestSignal, base);
161161
context_process_process_info_request_signal(ctx, request_signal, true);
162162
break;
163163
}
@@ -312,36 +312,93 @@ void context_process_kill_signal(Context *ctx, struct TermSignal *signal)
312312
context_update_flags(ctx, ~NoFlags, Killed);
313313
}
314314

315-
void context_process_process_info_request_signal(Context *ctx, struct BuiltInAtomRequestSignal *signal, bool process_table_locked)
315+
void context_process_process_info_request_signal(Context *ctx, struct ProcessInfoRequestSignal *signal, bool process_table_locked)
316316
{
317317
Context *target;
318318
if (process_table_locked) {
319319
target = globalcontext_get_process_nolock(ctx->global, signal->sender_pid);
320320
} else {
321321
target = globalcontext_get_process_lock(ctx->global, signal->sender_pid);
322322
}
323-
if (LIKELY(target)) {
323+
324+
if (UNLIKELY(!target)) {
325+
return;
326+
}
327+
328+
if (signal->mode == PROCESS_INFO_SINGLE) {
329+
term atom = signal->atoms[0];
324330
size_t term_size;
325-
if (context_get_process_info(ctx, NULL, &term_size, signal->atom, NULL)) {
326-
Heap heap;
327-
if (UNLIKELY(memory_init_heap(&heap, term_size) != MEMORY_GC_OK)) {
328-
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
329-
} else {
330-
term ret;
331-
if (context_get_process_info(ctx, &ret, NULL, signal->atom, &heap)) {
332-
mailbox_send_term_signal(target, TrapAnswerSignal, ret);
333-
} else {
334-
mailbox_send_immediate_signal(target, TrapExceptionSignal, ret);
335-
}
336-
memory_destroy_heap(&heap, ctx->global);
331+
if (!context_get_process_info(ctx, NULL, &term_size, atom, NULL)) {
332+
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
333+
goto done;
334+
}
335+
336+
Heap heap;
337+
if (UNLIKELY(memory_init_heap(&heap, term_size) != MEMORY_GC_OK)) {
338+
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
339+
goto done;
340+
}
341+
342+
term ret;
343+
if (context_get_process_info(ctx, &ret, NULL, atom, &heap)) {
344+
// return [] when unregistered (BEAM backward compatibility)
345+
if (atom == REGISTERED_NAME_ATOM && term_is_tuple(ret) && term_is_nil(term_get_tuple_element(ret, 1))) {
346+
ret = term_nil();
337347
}
348+
mailbox_send_term_signal(target, TrapAnswerSignal, ret);
338349
} else {
339-
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
350+
mailbox_send_immediate_signal(target, TrapExceptionSignal, ret);
351+
}
352+
memory_destroy_heap(&heap, ctx->global);
353+
} else {
354+
size_t total_size = 0;
355+
for (size_t i = 0; i < signal->len; i++) {
356+
size_t item_size;
357+
if (UNLIKELY(!context_get_process_info(ctx, NULL, &item_size, signal->atoms[i], NULL))) {
358+
mailbox_send_immediate_signal(target, TrapExceptionSignal, BADARG_ATOM);
359+
goto done;
360+
}
361+
total_size += item_size + CONS_SIZE;
362+
}
363+
364+
if (signal->len == 0) {
365+
mailbox_send_term_signal(target, TrapAnswerSignal, term_nil());
366+
goto done;
340367
}
341-
if (!process_table_locked) {
342-
globalcontext_get_process_unlock(ctx->global, target);
368+
369+
Heap heap;
370+
if (UNLIKELY(memory_init_heap(&heap, total_size) != MEMORY_GC_OK)) {
371+
mailbox_send_immediate_signal(target, TrapExceptionSignal, OUT_OF_MEMORY_ATOM);
372+
goto done;
373+
}
374+
375+
// Build list backwards to preserve input order
376+
term result = term_nil();
377+
bool build_ok = true;
378+
for (ssize_t i = (ssize_t) signal->len - 1; i >= 0; i--) {
379+
term item_result;
380+
if (UNLIKELY(!context_get_process_info(ctx, &item_result, NULL, signal->atoms[i], &heap))) {
381+
mailbox_send_immediate_signal(target, TrapExceptionSignal, item_result);
382+
build_ok = false;
383+
break;
384+
}
385+
386+
if (signal->mode == PROCESS_INFO_LIST_OMIT_UNREGISTERED && signal->atoms[i] == REGISTERED_NAME_ATOM && term_is_nil(term_get_tuple_element(item_result, 1))) {
387+
continue;
388+
}
389+
390+
result = term_list_prepend(item_result, result, &heap);
343391
}
344-
} // else: sender died
392+
if (LIKELY(build_ok)) {
393+
mailbox_send_term_signal(target, TrapAnswerSignal, result);
394+
}
395+
memory_destroy_heap(&heap, ctx->global);
396+
}
397+
398+
done:
399+
if (!process_table_locked) {
400+
globalcontext_get_process_unlock(ctx->global, target);
401+
}
345402
}
346403

347404
bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal)
@@ -525,6 +582,7 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
525582
case MESSAGE_QUEUE_LEN_ATOM:
526583
case REGISTERED_NAME_ATOM:
527584
case MEMORY_ATOM:
585+
case TRAP_EXIT_ATOM:
528586
ret_size = TUPLE_SIZE(2);
529587
break;
530588
case LINKS_ATOM: {
@@ -589,12 +647,8 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
589647
// registered_name for process or port..
590648
case REGISTERED_NAME_ATOM: {
591649
term name = globalcontext_get_registered_name_process(ctx->global, ctx->process_id);
592-
if (term_is_invalid_term((name))) {
593-
ret = term_nil(); // Set ret to an empty list to match erlang behaviour
594-
} else {
595-
term_put_tuple_element(ret, 0, REGISTERED_NAME_ATOM);
596-
term_put_tuple_element(ret, 1, name);
597-
}
650+
term_put_tuple_element(ret, 0, REGISTERED_NAME_ATOM);
651+
term_put_tuple_element(ret, 1, term_is_invalid_term(name) ? term_nil() : name);
598652
break;
599653
}
600654

@@ -630,6 +684,13 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
630684
break;
631685
}
632686

687+
// true if a process traps exits, otherwise false
688+
case TRAP_EXIT_ATOM: {
689+
term_put_tuple_element(ret, 0, TRAP_EXIT_ATOM);
690+
term_put_tuple_element(ret, 1, ctx->trap_exit ? TRUE_ATOM : FALSE_ATOM);
691+
break;
692+
}
693+
633694
// pids of linked processes
634695
case LINKS_ATOM: {
635696
term_put_tuple_element(ret, 0, LINKS_ATOM);

src/libAtomVM/context.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,10 +430,10 @@ void context_process_kill_signal(Context *ctx, struct TermSignal *signal);
430430
* @brief Process a process info request signal.
431431
*
432432
* @param ctx the context being executed
433-
* @param signal the process info signal
433+
* @param signal the process info request signal
434434
* @param process_table_locked whether process table is already locked
435435
*/
436-
void context_process_process_info_request_signal(Context *ctx, struct BuiltInAtomRequestSignal *signal, bool process_table_locked);
436+
void context_process_process_info_request_signal(Context *ctx, struct ProcessInfoRequestSignal *signal, bool process_table_locked);
437437

438438
/**
439439
* @brief Process a trap answer signal.

src/libAtomVM/jit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,8 @@ static Context *jit_process_signal_messages(Context *ctx, JITState *jit_state)
820820
break;
821821
}
822822
case ProcessInfoRequestSignal: {
823-
struct BuiltInAtomRequestSignal *request_signal
824-
= CONTAINER_OF(signal_message, struct BuiltInAtomRequestSignal, base);
823+
struct ProcessInfoRequestSignal *request_signal
824+
= CONTAINER_OF(signal_message, struct ProcessInfoRequestSignal, base);
825825
context_process_process_info_request_signal(ctx, request_signal, false);
826826
break;
827827
}

src/libAtomVM/mailbox.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ void mailbox_message_dispose(MailboxMessage *m, Heap *heap)
110110
break;
111111
}
112112
case ProcessInfoRequestSignal: {
113-
struct BuiltInAtomRequestSignal *request_signal
114-
= CONTAINER_OF(m, struct BuiltInAtomRequestSignal, base);
113+
struct ProcessInfoRequestSignal *request_signal
114+
= CONTAINER_OF(m, struct ProcessInfoRequestSignal, base);
115115
free(request_signal);
116116
break;
117117
}
@@ -291,19 +291,24 @@ void mailbox_send_immediate_signal(Context *c, enum MessageType type, term immed
291291
mailbox_post_message(c, &immediate_signal->base);
292292
}
293293

294-
void mailbox_send_built_in_atom_request_signal(
295-
Context *c, enum MessageType type, int32_t pid, term atom)
294+
void mailbox_send_process_info_request_signal(
295+
Context *c, int32_t sender_pid, process_info_mode_t mode, const term *atoms, size_t len)
296296
{
297-
struct BuiltInAtomRequestSignal *atom_request = malloc(sizeof(struct BuiltInAtomRequestSignal));
298-
if (IS_NULL_PTR(atom_request)) {
297+
struct ProcessInfoRequestSignal *signal = malloc(
298+
sizeof(struct ProcessInfoRequestSignal) + len * sizeof(term));
299+
if (IS_NULL_PTR(signal)) {
299300
fprintf(stderr, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
300301
return;
301302
}
302-
atom_request->base.type = type;
303-
atom_request->sender_pid = pid;
304-
atom_request->atom = atom;
303+
signal->base.type = ProcessInfoRequestSignal;
304+
signal->sender_pid = sender_pid;
305+
signal->mode = mode;
306+
signal->len = len;
307+
for (size_t i = 0; i < len; i++) {
308+
signal->atoms[i] = atoms[i];
309+
}
305310

306-
mailbox_post_message(c, &atom_request->base);
311+
mailbox_post_message(c, &signal->base);
307312
}
308313

309314
void mailbox_send_ref_signal(Context *c, enum MessageType type, uint64_t ref_ticks)

src/libAtomVM/mailbox.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,21 @@ struct ImmediateSignal
137137
term immediate;
138138
};
139139

140-
struct BuiltInAtomRequestSignal
140+
typedef enum
141+
{
142+
PROCESS_INFO_SINGLE,
143+
PROCESS_INFO_LIST,
144+
PROCESS_INFO_LIST_OMIT_UNREGISTERED,
145+
} process_info_mode_t;
146+
147+
struct ProcessInfoRequestSignal
141148
{
142149
MailboxMessage base;
143150

144151
int32_t sender_pid;
145-
term atom;
152+
process_info_mode_t mode;
153+
size_t len;
154+
term atoms[];
146155
};
147156

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

250259
/**
251-
* @brief Sends a built-in atom-based request signal to a certain mailbox.
260+
* @brief Sends a process info request signal to a certain mailbox.
252261
*
253262
* @param c the process context.
254-
* @param type the type of the signal
255263
* @param sender_pid the sender of the signal (to get the answer)
256-
* @param atom the built-in atom
264+
* @param mode controls result shape and registered_name handling
265+
* @param atoms array of atom terms to query
266+
* @param len number of atoms in the array
257267
*/
258-
void mailbox_send_built_in_atom_request_signal(
259-
Context *c, enum MessageType type, int32_t sender_pid, term atom);
268+
void mailbox_send_process_info_request_signal(
269+
Context *c, int32_t sender_pid, process_info_mode_t mode, const term *atoms, size_t len);
260270

261271
/**
262272
* @brief Sends a ref signal to a certain mailbox.

0 commit comments

Comments
 (0)