diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index cc85e4620b..59d30e0ec3 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -108,7 +108,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP glb->modules_lock = smp_rwlock_create(); if (IS_NULL_PTR(glb->modules_lock)) { - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -140,7 +140,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP smp_rwlock_destroy(glb->modules_lock); #endif - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -155,7 +155,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP smp_rwlock_destroy(glb->modules_lock); #endif - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -171,7 +171,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP smp_rwlock_destroy(glb->modules_lock); #endif - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -185,7 +185,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP smp_rwlock_destroy(glb->modules_lock); #endif - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -199,7 +199,7 @@ GlobalContext *globalcontext_new(void) #ifndef AVM_NO_SMP smp_rwlock_destroy(glb->modules_lock); #endif - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -215,7 +215,7 @@ GlobalContext *globalcontext_new(void) resource_type_destroy(glb->posix_fd_resource_type); #endif smp_rwlock_destroy(glb->modules_lock); - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -227,7 +227,7 @@ GlobalContext *globalcontext_new(void) resource_type_destroy(glb->posix_fd_resource_type); #endif smp_rwlock_destroy(glb->modules_lock); - free(glb->modules_table); + valueshashtable_destroy(glb->modules_table); atom_table_destroy(glb->atom_table); free(glb); return NULL; @@ -257,10 +257,24 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb) struct ListHead *item; struct ListHead *tmp; + while (true) { + struct ListHead *processes = synclist_rdlock(&glb->processes_table); + struct ListHead *first = list_first(processes); + if (first == processes) { + synclist_unlock(&glb->processes_table); + break; + } + Context *ctx = GET_LIST_ENTRY(first, Context, processes_table_head); + synclist_unlock(&glb->processes_table); + context_destroy(ctx); + } + int module_index = glb->loaded_modules_count; for (int i = 0; i < module_index; i++) { module_destroy(glb->modules_by_index[i]); } + free(glb->modules_by_index); + valueshashtable_destroy(glb->modules_table); struct ListHead *open_avm_packs = synclist_nolock(&glb->avmpack_data); MUTABLE_LIST_FOR_EACH (item, tmp, open_avm_packs) { @@ -318,6 +332,8 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb) synclist_destroy(&glb->registered_processes); synclist_destroy(&glb->processes_table); + atom_table_destroy(glb->atom_table); + free(glb); } diff --git a/src/libAtomVM/valueshashtable.c b/src/libAtomVM/valueshashtable.c index 5530421487..1fcfd76fb2 100644 --- a/src/libAtomVM/valueshashtable.c +++ b/src/libAtomVM/valueshashtable.c @@ -65,6 +65,23 @@ struct ValuesHashTable *valueshashtable_new(void) return htable; } +void valueshashtable_destroy(struct ValuesHashTable *hash_table) +{ + for (size_t i = 0; i < hash_table->capacity; i++) { + struct HNode *node = hash_table->buckets[i]; + while (node) { + struct HNode *next = node->next; + free(node); + node = next; + } + } +#ifndef AVM_NO_SMP + smp_rwlock_destroy(hash_table->lock); +#endif + free(hash_table->buckets); + free(hash_table); +} + int valueshashtable_insert(struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t value) { SMP_WRLOCK(hash_table); diff --git a/src/libAtomVM/valueshashtable.h b/src/libAtomVM/valueshashtable.h index 3aec410f11..800e577995 100644 --- a/src/libAtomVM/valueshashtable.h +++ b/src/libAtomVM/valueshashtable.h @@ -48,6 +48,7 @@ struct ValuesHashTable }; struct ValuesHashTable *valueshashtable_new(void); +void valueshashtable_destroy(struct ValuesHashTable *hash_table); int valueshashtable_insert(struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t value); uintptr_t valueshashtable_get_value(const struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t default_value); int valueshashtable_has_key(const struct ValuesHashTable *hash_table, uintptr_t key); diff --git a/src/platforms/esp32/components/avm_builtins/network_driver.c b/src/platforms/esp32/components/avm_builtins/network_driver.c index f5c59cff95..2ecbdbad76 100644 --- a/src/platforms/esp32/components/avm_builtins/network_driver.c +++ b/src/platforms/esp32/components/avm_builtins/network_driver.c @@ -1228,6 +1228,8 @@ static void start_network(Context *ctx, term pid, term ref, term config) data->owner_process_id = term_to_local_process_id(pid); data->ref_ticks = term_to_ref_ticks(ref); data->managed = roaming; + struct ESP32PlatformData *platform = ctx->global->platform_data; + platform->network_driver_data = data; esp_netif_t *sta_wifi_interface = NULL; if ((sta_wifi_config != NULL) || (roaming)) { @@ -1379,7 +1381,7 @@ static void start_network(Context *ctx, term pid, term ref, term config) return; } -static void stop_network(void) +static void stop_network(GlobalContext *global) { // Stop sntp (ignore OK, or not configured error) esp_sntp_stop(); @@ -1412,6 +1414,10 @@ static void stop_network(void) if (sta_wifi_interface != NULL) { esp_netif_destroy_default_wifi(sta_wifi_interface); } + + struct ESP32PlatformData *platform = global->platform_data; + free(platform->network_driver_data); + platform->network_driver_data = NULL; } static void get_sta_rssi(Context *ctx, term pid, term ref) @@ -1912,7 +1918,7 @@ static NativeHandlerResult consume_mailbox(Context *ctx) break; case NetworkStopCmd: cmd_terminate = true; - stop_network(); + stop_network(ctx->global); break; case NetworkScanCmd: wifi_scan(ctx, pid, ref, config); @@ -1994,12 +2000,10 @@ Context *network_driver_create_port(GlobalContext *global, term opts) static void network_driver_destroy(GlobalContext *global) { - UNUSED(global); - // Unregister the scan handler first, since stop_network() does not handle // it and esp_wifi_stop() may post WIFI_EVENT_SCAN_DONE for an aborted scan. esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, &scan_done_handler); - stop_network(); + stop_network(global); } REGISTER_PORT_DRIVER(network, network_driver_init, network_driver_destroy, network_driver_create_port) diff --git a/src/platforms/esp32/components/avm_sys/include/esp32_sys.h b/src/platforms/esp32/components/avm_sys/include/esp32_sys.h index e38368d3db..3f0bc4dec0 100644 --- a/src/platforms/esp32/components/avm_sys/include/esp32_sys.h +++ b/src/platforms/esp32/components/avm_sys/include/esp32_sys.h @@ -69,6 +69,9 @@ struct ESP32PlatformData struct SyncList sockets; struct ListHead ready_connections; + // network_driver + void *network_driver_data; + #ifndef AVM_NO_SMP Mutex *entropy_mutex; #endif @@ -89,7 +92,7 @@ struct ESP32PlatformData extern QueueSetHandle_t event_set; extern QueueHandle_t event_queue; -void esp32_sys_queue_init(); +void esp32_sys_queue_init(void); void socket_init(Context *ctx, term opts); diff --git a/src/platforms/esp32/components/avm_sys/sys.c b/src/platforms/esp32/components/avm_sys/sys.c index 10909d9750..679405634a 100644 --- a/src/platforms/esp32/components/avm_sys/sys.c +++ b/src/platforms/esp32/components/avm_sys/sys.c @@ -113,8 +113,12 @@ static const char *const revision_atom = "\x8" "revision"; QueueHandle_t event_queue = NULL; QueueSetHandle_t event_set = NULL; -void esp32_sys_queue_init() +void esp32_sys_queue_init(void) { + if (event_set != NULL) { + return; + } + event_set = xQueueCreateSet(EVENT_QUEUE_LEN * 4); event_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(void *)); xQueueAddToSet(event_queue, event_set); @@ -230,6 +234,7 @@ void sys_init_platform(GlobalContext *glb) glb->platform_data = platform; platform->select_thread_exit = false; platform->select_events_poll_count = -1; + platform->network_driver_data = NULL; esp_vfs_eventfd_config_t eventfd_config = ESP_VFS_EVENTD_CONFIG_DEFAULT(); esp_err_t err = esp_vfs_eventfd_register(&eventfd_config); if (err == ESP_OK) { diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 1fc46f33f0..ca4f4acb4b 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -132,10 +132,28 @@ static void eth_stop(esp_netif_t *eth_netif) } #endif -term avm_test_case(const char *test_module) +static void prepare_event_queue(void) { esp32_sys_queue_init(); + QueueSetMemberHandle_t source; + while ((source = xQueueSelectFromSet(event_set, 0)) != NULL) { + if (UNLIKELY(source != event_queue)) { + fprintf(stderr, "Stale member in ESP32 event queue set.\n"); + AVM_ABORT(); + } + + void *ignored; + if (UNLIKELY(xQueueReceive(event_queue, &ignored, 0) != pdTRUE)) { + AVM_ABORT(); + } + } +} + +term avm_test_case(const char *test_module) +{ + prepare_event_queue(); + GlobalContext *glb = globalcontext_new(); TEST_ASSERT(glb != NULL); @@ -183,7 +201,7 @@ term avm_test_case(const char *test_module) #ifndef AVM_NO_JIT TEST_CASE("test_jit_compile", "[test_run]") { - esp32_sys_queue_init(); + prepare_event_queue(); GlobalContext *glb = globalcontext_new(); TEST_ASSERT(glb != NULL); diff --git a/tests/test-structs.c b/tests/test-structs.c index 52ce22dcd2..eb206230a4 100644 --- a/tests/test-structs.c +++ b/tests/test-structs.c @@ -180,6 +180,8 @@ void test_valueshashtable(void) assert(valueshashtable_get_value(htable, 0xBBDDBBDD + i, 0xCAFEBABE) == 0xEEFFEEFFL + i); assert(valueshashtable_get_value(htable, 0xABDDBBDD + i, 0xCAFEBABE) == 0xCAFEBABE); } + + valueshashtable_destroy(htable); } atom_index_t insert_atoms_into_atom_table(struct AtomTable *table)