Skip to content

Commit 4d4e14e

Browse files
committed
Implement erlang:demonitor/2
Signed-off-by: Paul Guyot <[email protected]>
1 parent 2546861 commit 4d4e14e

File tree

12 files changed

+191
-9
lines changed

12 files changed

+191
-9
lines changed

src/libAtomVM/context.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal)
166166
return true;
167167
}
168168

169+
void context_process_flush_monitor_signal(Context *ctx, uint64_t ref_ticks, bool info)
170+
{
171+
context_update_flags(ctx, ~Trap, NoFlags);
172+
bool result = true;
173+
mailbox_reset(&ctx->mailbox);
174+
term msg;
175+
while (mailbox_peek(ctx, &msg)) {
176+
if (term_is_tuple(msg)
177+
&& term_get_tuple_arity(msg) == 5
178+
&& term_get_tuple_element(msg, 0) == DOWN_ATOM
179+
&& term_is_reference(term_get_tuple_element(msg, 1))
180+
&& term_to_ref_ticks(term_get_tuple_element(msg, 1)) == ref_ticks) {
181+
mailbox_remove_message(&ctx->mailbox, &ctx->heap);
182+
// If option info is combined with option flush, false is returned if a flush was needed, otherwise true.
183+
result = !info;
184+
} else {
185+
mailbox_next(&ctx->mailbox);
186+
}
187+
}
188+
mailbox_reset(&ctx->mailbox);
189+
ctx->x[0] = result ? TRUE_ATOM : FALSE_ATOM;
190+
}
191+
169192
void context_update_flags(Context *ctx, int mask, int value) CLANG_THREAD_SANITIZE_SAFE
170193
{
171194
#ifndef AVM_NO_SMP

src/libAtomVM/context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,15 @@ void context_process_process_info_request_signal(Context *ctx, struct BuiltInAto
360360
*/
361361
bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal);
362362

363+
/**
364+
* @brief Process a flush monitor signal.
365+
*
366+
* @param ctx the context being executed
367+
* @param ref_ticks the monitor reference
368+
* @param info whether to return FALSE_ATOM if no message was flushed.
369+
*/
370+
void context_process_flush_monitor_signal(Context *ctx, uint64_t ref_ticks, bool info);
371+
363372
/**
364373
* @brief Get process information.
365374
*

src/libAtomVM/defaultatoms.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ static const char *const close_atom = "\x5" "close";
131131
static const char *const closed_atom = "\x6" "closed";
132132
static const char *const port_atom = "\x4" "port";
133133

134+
static const char *const info_atom = "\x4" "info";
135+
134136
void defaultatoms_init(GlobalContext *glb)
135137
{
136138
int ok = 1;
@@ -246,6 +248,8 @@ void defaultatoms_init(GlobalContext *glb)
246248
ok &= globalcontext_insert_atom(glb, closed_atom) == CLOSED_ATOM_INDEX;
247249
ok &= globalcontext_insert_atom(glb, port_atom) == PORT_ATOM_INDEX;
248250

251+
ok &= globalcontext_insert_atom(glb, info_atom) == INFO_ATOM_INDEX;
252+
249253
if (!ok) {
250254
AVM_ABORT();
251255
}

src/libAtomVM/defaultatoms.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ extern "C" {
140140
#define CLOSED_ATOM_INDEX 89
141141
#define PORT_ATOM_INDEX 90
142142

143-
#define PLATFORM_ATOMS_BASE_INDEX 91
143+
#define INFO_ATOM_INDEX 91
144+
145+
#define PLATFORM_ATOMS_BASE_INDEX 92
144146

145147
#define FALSE_ATOM TERM_FROM_ATOM_INDEX(FALSE_ATOM_INDEX)
146148
#define TRUE_ATOM TERM_FROM_ATOM_INDEX(TRUE_ATOM_INDEX)
@@ -255,6 +257,8 @@ extern "C" {
255257
#define CLOSED_ATOM TERM_FROM_ATOM_INDEX(CLOSED_ATOM_INDEX)
256258
#define PORT_ATOM TERM_FROM_ATOM_INDEX(PORT_ATOM_INDEX)
257259

260+
#define INFO_ATOM TERM_FROM_ATOM_INDEX(INFO_ATOM_INDEX)
261+
258262
void defaultatoms_init(GlobalContext *glb);
259263

260264
void platform_defaultatoms_init(GlobalContext *glb);

src/libAtomVM/globalcontext.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ Module *globalcontext_get_module_by_index(GlobalContext *global, int index)
438438
return result;
439439
}
440440

441-
void globalcontext_demonitor(GlobalContext *global, uint64_t ref_ticks)
441+
bool globalcontext_demonitor(GlobalContext *global, uint64_t ref_ticks)
442442
{
443443
struct ListHead *pitem;
444444

@@ -453,10 +453,11 @@ void globalcontext_demonitor(GlobalContext *global, uint64_t ref_ticks)
453453
list_remove(&monitor->monitor_list_head);
454454
free(monitor);
455455
synclist_unlock(&global->processes_table);
456-
return;
456+
return true;
457457
}
458458
}
459459
}
460460

461461
synclist_unlock(&global->processes_table);
462+
return false;
462463
}

src/libAtomVM/globalcontext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ Module *globalcontext_get_module_by_index(GlobalContext *global, int index);
354354
*/
355355
Module *globalcontext_get_module(GlobalContext *global, AtomString module_name_atom);
356356

357-
void globalcontext_demonitor(GlobalContext *global, uint64_t ref_ticks);
357+
bool globalcontext_demonitor(GlobalContext *global, uint64_t ref_ticks);
358358
void globalcontext_unlink(GlobalContext *global, term pid);
359359

360360
#ifndef __cplusplus

src/libAtomVM/mailbox.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ void mailbox_message_dispose(MailboxMessage *m, Heap *heap)
105105
free(atom_signal);
106106
break;
107107
}
108+
case FlushMonitorSignal:
109+
case FlushInfoMonitorSignal: {
110+
struct RefSignal *ref_signal = CONTAINER_OF(m, struct RefSignal, base);
111+
free(ref_signal);
112+
break;
113+
}
108114
case GCSignal:
109115
free(m);
110116
break;
@@ -242,6 +248,19 @@ void mailbox_send_built_in_atom_request_signal(
242248
mailbox_post_message(c, &atom_request->base);
243249
}
244250

251+
void mailbox_send_ref_signal(Context *c, enum MessageType type, uint64_t ref_ticks)
252+
{
253+
struct RefSignal *ref_signal = malloc(sizeof(struct RefSignal));
254+
if (IS_NULL_PTR(ref_signal)) {
255+
fprintf(stderr, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
256+
return;
257+
}
258+
ref_signal->base.type = type;
259+
ref_signal->ref_ticks = ref_ticks;
260+
261+
mailbox_post_message(c, &ref_signal->base);
262+
}
263+
245264
void mailbox_send_empty_body_signal(Context *c, enum MessageType type)
246265
{
247266
MailboxMessage *m = malloc(sizeof(MailboxMessage));

src/libAtomVM/mailbox.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ enum MessageType
6464
ProcessInfoRequestSignal,
6565
TrapAnswerSignal,
6666
TrapExceptionSignal,
67+
FlushMonitorSignal,
68+
FlushInfoMonitorSignal,
6769
};
6870

6971
struct MailboxMessage
@@ -110,6 +112,13 @@ struct BuiltInAtomRequestSignal
110112
term atom;
111113
};
112114

115+
struct RefSignal
116+
{
117+
MailboxMessage base;
118+
119+
uint64_t ref_ticks;
120+
};
121+
113122
typedef struct
114123
{
115124
// Outer list is inserted into by other processes and protected by a CAS
@@ -197,6 +206,15 @@ void mailbox_send_built_in_atom_signal(Context *c, enum MessageType type, term a
197206
void mailbox_send_built_in_atom_request_signal(
198207
Context *c, enum MessageType type, int32_t sender_pid, term atom);
199208

209+
/**
210+
* @brief Sends a ref signal to a certain mailbox.
211+
*
212+
* @param c the process context.
213+
* @param type the type of the signal
214+
* @param ref_ticks the ref
215+
*/
216+
void mailbox_send_ref_signal(Context *c, enum MessageType type, uint64_t ref_ticks);
217+
200218
/**
201219
* @brief Sends an empty body signal to a certain mailbox.
202220
*

src/libAtomVM/nifs.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3087,16 +3087,28 @@ static term nif_erlang_monitor(Context *ctx, int argc, term argv[])
30873087

30883088
static term nif_erlang_demonitor(Context *ctx, int argc, term argv[])
30893089
{
3090-
UNUSED(argc);
3091-
30923090
term ref = argv[0];
3091+
bool flush = false;
3092+
bool info = false;
3093+
3094+
if (argc == 2) {
3095+
term options = argv[1];
3096+
VALIDATE_VALUE(options, term_is_list);
3097+
flush = interop_proplist_get_value_default(options, FLUSH_ATOM, FALSE_ATOM) == TRUE_ATOM;
3098+
info = interop_proplist_get_value_default(options, INFO_ATOM, FALSE_ATOM) == TRUE_ATOM;
3099+
}
30933100

30943101
VALIDATE_VALUE(ref, term_is_reference);
30953102
uint64_t ref_ticks = term_to_ref_ticks(ref);
30963103

3097-
globalcontext_demonitor(ctx->global, ref_ticks);
3104+
bool result = globalcontext_demonitor(ctx->global, ref_ticks);
3105+
if (flush) {
3106+
mailbox_send_ref_signal(ctx, info ? FlushInfoMonitorSignal : FlushMonitorSignal, ref_ticks);
3107+
context_update_flags(ctx, ~NoFlags, Trap);
3108+
return term_invalid_term();
3109+
}
30983110

3099-
return TRUE_ATOM;
3111+
return !info || result ? TRUE_ATOM : FALSE_ATOM;
31003112
}
31013113

31023114
static term nif_erlang_link(Context *ctx, int argc, term argv[])

src/libAtomVM/nifs.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ erlang:make_tuple/2, &make_tuple_nif
7474
erlang:memory/1, &memory_nif
7575
erlang:monitor/2, &monitor_nif
7676
erlang:demonitor/1, &demonitor_nif
77+
erlang:demonitor/2, &demonitor_nif
7778
erlang:is_process_alive/1, &is_process_alive_nif
7879
erlang:register/2, &register_nif
7980
erlang:unregister/1, &unregister_nif

0 commit comments

Comments
 (0)