Skip to content

Commit 4682e15

Browse files
authored
Merge pull request atomvm#598 from pguyot/w21/fix-synchronization-issue-with-refc-binaries
Fix synchronization issue with refc binaries
2 parents e618631 + 02c1a3a commit 4682e15

File tree

11 files changed

+83
-41
lines changed

11 files changed

+83
-41
lines changed

src/libAtomVM/context.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void context_destroy(Context *ctx)
118118

119119
free(ctx->fr);
120120

121-
memory_destroy_heap(&ctx->heap);
121+
memory_destroy_heap(&ctx->heap, ctx->global);
122122

123123
dictionary_destroy(&ctx->dictionary);
124124

src/libAtomVM/globalcontext.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "context.h"
2828
#include "defaultatoms.h"
2929
#include "list.h"
30+
#include "refc_binary.h"
3031
#include "synclist.h"
3132
#include "sys.h"
3233
#include "utils.h"
@@ -165,7 +166,16 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb)
165166
#endif
166167
synclist_destroy(&glb->registered_processes);
167168
synclist_destroy(&glb->processes_table);
169+
// Destroy every remaining refc binaries.
170+
struct ListHead *item;
171+
struct ListHead *tmp;
172+
struct ListHead *refc_binaries = synclist_nolock(&glb->refc_binaries);
173+
MUTABLE_LIST_FOR_EACH (item, tmp, refc_binaries) {
174+
struct RefcBinary *refc = GET_LIST_ENTRY(item, struct RefcBinary, head);
175+
refc_binary_destroy(refc, glb);
176+
}
168177
synclist_destroy(&glb->refc_binaries);
178+
169179
synclist_destroy(&glb->avmpack_data);
170180
free(glb);
171181
}

src/libAtomVM/memory.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ static enum MemoryGCResult memory_gc(Context *ctx, size_t new_size, size_t num_r
179179

180180
ctx->heap.heap_ptr = temp_end;
181181

182-
memory_sweep_mso_list(old_mso_list);
182+
memory_sweep_mso_list(old_mso_list, ctx->global);
183183
ctx->heap.root->mso_list = new_mso_list;
184184

185185
memory_destroy_heap_fragment(old_root_fragment);
@@ -598,7 +598,7 @@ void memory_heap_append_fragment(Heap *heap, HeapFragment *fragment, term mso_li
598598
}
599599
}
600600

601-
void memory_sweep_mso_list(term mso_list)
601+
void memory_sweep_mso_list(term mso_list, GlobalContext *global)
602602
{
603603
term l = mso_list;
604604
while (l != term_nil()) {
@@ -610,7 +610,7 @@ void memory_sweep_mso_list(term mso_list)
610610
// it has been moved, so it is referenced
611611
} else if (term_is_refc_binary(h) && !term_refc_binary_is_const(h)) {
612612
// unreferenced binary; decrement reference count
613-
refc_binary_decrement_refcount((struct RefcBinary *) term_refc_binary_ptr(h));
613+
refc_binary_decrement_refcount((struct RefcBinary *) term_refc_binary_ptr(h), global);
614614
}
615615
l = term_get_list_tail(l);
616616
}

src/libAtomVM/memory.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ extern "C" {
4343
typedef struct Context Context;
4444
#endif
4545

46+
#ifndef TYPEDEF_GLOBAL_CONTEXT
47+
#define TYPEDEF_GLOBAL_CONTEXT
48+
typedef struct GlobalContext GlobalContext;
49+
#endif
50+
4651
enum MemoryGCResult
4752
{
4853
MEMORY_GC_OK = 0,
@@ -99,10 +104,10 @@ typedef struct Heap Heap;
99104
Heap name; \
100105
memory_init_heap_root_fragment(&name, (HeapFragment *) &(name##__root__), size);
101106

102-
#define END_WITH_STACK_HEAP(name) \
103-
memory_sweep_mso_list(name.root->mso_list); \
104-
if (name.root->next) { \
105-
memory_destroy_heap_fragment(name.root->next); \
107+
#define END_WITH_STACK_HEAP(name, global) \
108+
memory_sweep_mso_list(name.root->mso_list, global); \
109+
if (name.root->next) { \
110+
memory_destroy_heap_fragment(name.root->next); \
106111
}
107112

108113
// mso_list is the first term for message storage
@@ -303,8 +308,9 @@ static inline void memory_heap_append_heap(Heap *target, Heap *source)
303308
* function may be called in a copy even, such as in a process spawn, or in
304309
* the copy of a term to or from a process mailbox.
305310
* @param mso_list the list of mark-sweep object in a heap "space"
311+
* @param global the global context
306312
*/
307-
void memory_sweep_mso_list(term mso_list);
313+
void memory_sweep_mso_list(term mso_list, GlobalContext *global);
308314

309315
/**
310316
* @brief Destroy a chain of heap fragments.
@@ -324,9 +330,9 @@ static inline void memory_destroy_heap_fragment(HeapFragment *fragment)
324330
/**
325331
* @brief Destroy a root heap. First sweep its mso list.
326332
*/
327-
static inline void memory_destroy_heap(Heap *heap)
333+
static inline void memory_destroy_heap(Heap *heap, GlobalContext *global)
328334
{
329-
memory_sweep_mso_list(heap->root->mso_list);
335+
memory_sweep_mso_list(heap->root->mso_list, global);
330336
memory_destroy_heap_fragment(heap->root);
331337
}
332338

src/libAtomVM/refc_binary.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,23 @@ void refc_binary_increment_refcount(struct RefcBinary *refc)
5555
refc->ref_count++;
5656
}
5757

58-
bool refc_binary_decrement_refcount(struct RefcBinary *refc)
58+
bool refc_binary_decrement_refcount(struct RefcBinary *refc, struct GlobalContext *global)
5959
{
6060
if (--refc->ref_count == 0) {
61-
list_remove(&refc->head);
62-
free(refc);
61+
synclist_remove(&global->refc_binaries, &refc->head);
62+
refc_binary_destroy(refc, global);
6363
return true;
6464
}
6565
return false;
6666
}
6767

68+
void refc_binary_destroy(struct RefcBinary *refc, struct GlobalContext *global)
69+
{
70+
UNUSED(global);
71+
72+
free(refc);
73+
}
74+
6875
term refc_binary_create_binary_info(Context *ctx)
6976
{
7077
size_t len = 0;

src/libAtomVM/refc_binary.h

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ extern "C" {
3030

3131
#include "list.h"
3232
#include "smp.h"
33+
#ifndef TYPEDEF_CONTEXT
34+
#define TYPEDEF_CONTEXT
35+
typedef struct Context Context;
36+
#endif
37+
38+
#ifndef TYPEDEF_GLOBAL_CONTEXT
39+
#define TYPEDEF_GLOBAL_CONTEXT
40+
typedef struct GlobalContext GlobalContext;
41+
#endif
3342

3443
struct RefcBinary
3544
{
@@ -41,10 +50,9 @@ struct RefcBinary
4150
/**
4251
* @brief Create a reference-counted binary outside of the process heap
4352
*
44-
* @details This function will create a reference-counted binary outside of the context heap. If the binary is non-const,
45-
* a blob will be allocated in the VM memory (e.g., via malloc). The allocated data will include
46-
* an internal data structure that includes the data size and reference count. If the supplied
47-
* data is non-NULL, the supplied data will be copied to the newly allocated region.
53+
* @details This function will create a reference-counted binary outside of the context heap.
54+
* A blob will be allocated in the VM memory (e.g., via malloc). The allocated data will include
55+
* an internal data structure that includes the data size and reference count.
4856
* @param size the size of the data to create
4957
* @returns a pointer to the out-of-context data.
5058
*/
@@ -67,12 +75,23 @@ void refc_binary_increment_refcount(struct RefcBinary *ptr);
6775
/**
6876
* @brief Decrement the reference count on the refc binary
6977
*
70-
* @details This function will free the the refc binary if the
78+
* @details This function will call `refc_binary_destroy` if the
7179
* reference count reaches 0.
7280
* @param ptr the refc binary
81+
* @param global the global context
7382
* @return true if the refc binary was free'd; false, otherwise
7483
*/
75-
bool refc_binary_decrement_refcount(struct RefcBinary *ptr);
84+
bool refc_binary_decrement_refcount(struct RefcBinary *ptr, GlobalContext *global);
85+
86+
/**
87+
* @brief Destroy a refc binary after its reference count reached 0.
88+
*
89+
* @details This function will call the destructor if the refc binary is a
90+
* resource and will free the refc binary.
91+
* @param refc the binary to destroy
92+
* @param global the global context
93+
*/
94+
void refc_binary_destroy(struct RefcBinary *refc, struct GlobalContext *global);
7695

7796
/**
7897
* TODO consider implementing erlang:memory/0,1 instead

src/platforms/esp32/components/avm_builtins/gpio_driver.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ EventListener *gpio_interrupt_callback(GlobalContext *glb, EventListener *listen
301301

302302
globalcontext_send_message(glb, listening_pid, int_msg);
303303

304-
END_WITH_STACK_HEAP(heap);
304+
END_WITH_STACK_HEAP(heap, glb);
305305

306306
return listener;
307307
}

src/platforms/esp32/components/avm_builtins/network_driver.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ static void send_got_ip(struct ClientData *data, tcpip_adapter_ip_info_t *info)
135135
term reply = port_heap_create_tuple2(&heap, make_atom(data->global, sta_got_ip_atom), ip_info);
136136
send_term(&heap, data, reply);
137137
}
138-
END_WITH_STACK_HEAP(heap);
138+
END_WITH_STACK_HEAP(heap, data->global);
139139
}
140140

141141
static void send_sta_connected(struct ClientData *data)
@@ -147,7 +147,7 @@ static void send_sta_connected(struct ClientData *data)
147147
{
148148
send_term(&heap, data, make_atom(data->global, sta_connected_atom));
149149
}
150-
END_WITH_STACK_HEAP(heap);
150+
END_WITH_STACK_HEAP(heap, data->global);
151151
}
152152

153153
static void send_sta_disconnected(struct ClientData *data)
@@ -159,7 +159,7 @@ static void send_sta_disconnected(struct ClientData *data)
159159
{
160160
send_term(&heap, data, make_atom(data->global, sta_disconnected_atom));
161161
}
162-
END_WITH_STACK_HEAP(heap);
162+
END_WITH_STACK_HEAP(heap, data->global);
163163
}
164164

165165
static void send_ap_started(struct ClientData *data)
@@ -171,7 +171,7 @@ static void send_ap_started(struct ClientData *data)
171171
{
172172
send_term(&heap, data, make_atom(data->global, ap_started_atom));
173173
}
174-
END_WITH_STACK_HEAP(heap);
174+
END_WITH_STACK_HEAP(heap, data->global);
175175
}
176176

177177
static void send_atom_mac(struct ClientData *data, term atom, uint8_t *mac)
@@ -183,7 +183,7 @@ static void send_atom_mac(struct ClientData *data, term atom, uint8_t *mac)
183183
term reply = port_heap_create_tuple2(&heap, atom, mac_term);
184184
send_term(&heap, data, reply);
185185
}
186-
END_WITH_STACK_HEAP(heap);
186+
END_WITH_STACK_HEAP(heap, data->global);
187187
}
188188

189189
static void send_ap_sta_connected(struct ClientData *data, uint8_t *mac)
@@ -208,7 +208,7 @@ static void send_ap_sta_ip_assigned(struct ClientData *data, esp_ip4_addr_t *ip)
208208
term reply = port_heap_create_tuple2(&heap, make_atom(data->global, ap_sta_ip_assigned_atom), ip_term);
209209
send_term(&heap, data, reply);
210210
}
211-
END_WITH_STACK_HEAP(heap);
211+
END_WITH_STACK_HEAP(heap, data->global);
212212
}
213213

214214
static void send_sntp_sync(struct ClientData *data, struct timeval *tv)
@@ -222,7 +222,7 @@ static void send_sntp_sync(struct ClientData *data, struct timeval *tv)
222222
term reply = port_heap_create_tuple2(&heap, make_atom(data->global, sntp_sync_atom), tv_tuple);
223223
send_term(&heap, data, reply);
224224
}
225-
END_WITH_STACK_HEAP(heap);
225+
END_WITH_STACK_HEAP(heap, data->global);
226226
}
227227

228228
#define UNLIKELY_NOT_ESP_OK(E) UNLIKELY((E) != ESP_OK)

src/platforms/esp32/components/avm_builtins/socket_driver.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ EventListener *socket_events_handler(GlobalContext *glb, EventListener *listener
269269
term_put_tuple_element(message, 0, globalcontext_make_atom(glb, netconn_event_internal));
270270
term_put_tuple_element(message, 1, term_from_int(event.len));
271271
globalcontext_send_message(glb, socket->process_id, message);
272-
END_WITH_STACK_HEAP(heap)
272+
END_WITH_STACK_HEAP(heap, glb)
273273
}
274274
}
275275
return listener;

src/platforms/esp32/components/avm_builtins/uart_driver.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ EventListener *uart_interrupt_callback(GlobalContext *glb, EventListener *listen
129129
int local_pid = term_to_local_process_id(uart_data->reader_process_pid);
130130
globalcontext_send_message(glb, local_pid, result_tuple);
131131

132-
memory_destroy_heap(&heap);
132+
memory_destroy_heap(&heap, glb);
133133

134134
uart_data->reader_process_pid = term_invalid_term();
135135
uart_data->reader_ref_ticks = 0;

0 commit comments

Comments
 (0)