diff --git a/src/libAtomVM/ets.c b/src/libAtomVM/ets.c index 26ad38b92..58dbd1eb8 100644 --- a/src/libAtomVM/ets.c +++ b/src/libAtomVM/ets.c @@ -413,23 +413,48 @@ EtsErrorCode ets_lookup_element(term name_or_ref, term key, size_t pos, term *re return EtsOk; } -EtsErrorCode ets_delete(term name_or_ref, term key, term *ret, Context *ctx) +static EtsErrorCode ets_table_delete(struct EtsTable *ets_table, term key, term *ret, Context *ctx) { - struct EtsTable *ets_table = term_is_atom(name_or_ref) ? ets_get_table_by_name(&ctx->global->ets, name_or_ref, TableAccessRead) : ets_get_table_by_ref(&ctx->global->ets, term_to_ref_ticks(name_or_ref), TableAccessRead); - if (ets_table == NULL) { - return EtsTableNotFound; - } - if (ets_table->access_type != EtsAccessPublic && ets_table->owner_process_id != ctx->process_id) { - SMP_UNLOCK(ets_table); return EtsPermissionDenied; } bool _res = ets_hashtable_remove(ets_table->hashtable, key, ets_table->keypos, ctx->global); UNUSED(_res); - SMP_UNLOCK(ets_table); *ret = TRUE_ATOM; + return EtsOk; +} +EtsErrorCode ets_drop_table(term name_or_ref, term *ret, Context *ctx) +{ + struct EtsTable *ets_table = term_is_atom(name_or_ref) ? ets_get_table_by_name(&ctx->global->ets, name_or_ref, TableAccessWrite) : ets_get_table_by_ref(&ctx->global->ets, term_to_ref_ticks(name_or_ref), TableAccessWrite); + if (IS_NULL_PTR(ets_table)) { + return EtsTableNotFound; + } + if (ets_table->access_type != EtsAccessPublic && ets_table->owner_process_id != ctx->process_id) { + return EtsPermissionDenied; + } + + synclist_wrlock(&ctx->global->ets.ets_tables); + SMP_UNLOCK(ets_table); + list_remove(&ets_table->head); + ets_table_destroy(ets_table, ctx->global); + synclist_unlock(&ctx->global->ets.ets_tables); + + *ret = TRUE_ATOM; return EtsOk; } + +EtsErrorCode ets_delete(term name_or_ref, term key, term *ret, Context *ctx) +{ + struct EtsTable *ets_table = term_is_atom(name_or_ref) ? ets_get_table_by_name(&ctx->global->ets, name_or_ref, TableAccessRead) : ets_get_table_by_ref(&ctx->global->ets, term_to_ref_ticks(name_or_ref), TableAccessRead); + if (IS_NULL_PTR(ets_table)) { + return EtsTableNotFound; + } + + EtsErrorCode res = ets_table_delete(ets_table, key, ret, ctx); + + SMP_UNLOCK(ets_table); + return res; +} diff --git a/src/libAtomVM/ets.h b/src/libAtomVM/ets.h index 1d09125fa..d25117b7e 100644 --- a/src/libAtomVM/ets.h +++ b/src/libAtomVM/ets.h @@ -77,6 +77,7 @@ EtsErrorCode ets_insert(term ref, term entry, Context *ctx); EtsErrorCode ets_lookup(term ref, term key, term *ret, Context *ctx); EtsErrorCode ets_lookup_element(term ref, term key, size_t pos, term *ret, Context *ctx); EtsErrorCode ets_delete(term ref, term key, term *ret, Context *ctx); +EtsErrorCode ets_drop_table(term ref, term *ret, Context *ctx); #ifdef __cplusplus } diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index dd4e35ac6..bdca3631c 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -3393,15 +3393,17 @@ static term nif_ets_lookup_element(Context *ctx, int argc, term argv[]) static term nif_ets_delete(Context *ctx, int argc, term argv[]) { - UNUSED(argc); - term ref = argv[0]; VALIDATE_VALUE(ref, is_ets_table_id); - - term key = argv[1]; - term ret = term_invalid_term(); - EtsErrorCode result = ets_delete(ref, key, &ret, ctx); + EtsErrorCode result; + if (argc == 2) { + term key = argv[1]; + result = ets_delete(ref, key, &ret, ctx); + } else { + result = ets_drop_table(ref, &ret, ctx); + } + switch (result) { case EtsOk: return ret; diff --git a/src/libAtomVM/nifs.gperf b/src/libAtomVM/nifs.gperf index 0cc99e02c..291bb1b63 100644 --- a/src/libAtomVM/nifs.gperf +++ b/src/libAtomVM/nifs.gperf @@ -134,6 +134,7 @@ ets:insert/2, &ets_insert_nif ets:lookup/2, &ets_lookup_nif ets:lookup_element/3, &ets_lookup_element_nif ets:delete/2, &ets_delete_nif +ets:delete/1, &ets_delete_nif atomvm:add_avm_pack_binary/2, &atomvm_add_avm_pack_binary_nif atomvm:add_avm_pack_file/2, &atomvm_add_avm_pack_file_nif atomvm:close_avm_pack/2, &atomvm_close_avm_pack_nif diff --git a/tests/erlang_tests/test_ets.erl b/tests/erlang_tests/test_ets.erl index eafc2b65b..4eadf64c9 100644 --- a/tests/erlang_tests/test_ets.erl +++ b/tests/erlang_tests/test_ets.erl @@ -32,6 +32,7 @@ start() -> ok = test_public_access(), ok = test_lookup_element(), ok = test_insert_list(), + ok = test_delete_table(), 0. test_basic() -> @@ -366,3 +367,15 @@ test_insert_list() -> end), expect_failure(fun() -> ets:insert(Tid, [{}]) end), ok. + +test_delete_table() -> + Tid = ets:new(test_delete_table, []), + true = ets:insert(Tid, {foo, tapas}), + [{foo, tapas}] = ets:lookup(Tid, foo), + true = ets:delete(Tid), + ok = expect_failure( + fun() -> ets:insert(Tid, {gnu, gnat}) end + ), + Ntid = ets:new(test_delete_table, []), + true = ets:delete(Ntid), + ok.