28
28
#include "overflow_helpers.h"
29
29
#include "term.h"
30
30
31
+ #define ETS_NO_INDEX SIZE_MAX
32
+ #define ETS_ANY_PROCESS -1
33
+
31
34
#ifndef AVM_NO_SMP
32
35
#define SMP_RDLOCK (table ) smp_rwlock_rdlock(table->lock)
33
36
#define SMP_WRLOCK (table ) smp_rwlock_wrlock(table->lock)
@@ -81,51 +84,40 @@ static void ets_add_table(struct Ets *ets, struct EtsTable *ets_table)
81
84
synclist_unlock (& ets -> ets_tables );
82
85
}
83
86
84
- static struct EtsTable * ets_get_table_by_ref (struct Ets * ets , uint64_t ref , TableAccessType access_type )
87
+ static struct EtsTable * ets_acquire_table (struct Ets * ets , int32_t process_id , term name_or_ref , TableAccessType requested_access_type )
85
88
{
86
- struct ListHead * ets_tables_list = synclist_rdlock (& ets -> ets_tables );
87
- struct ListHead * item ;
88
- struct EtsTable * ret = NULL ;
89
- LIST_FOR_EACH (item , ets_tables_list ) {
90
- struct EtsTable * table = GET_LIST_ENTRY (item , struct EtsTable , head );
91
- if (table -> ref_ticks == ref ) {
92
- switch (access_type ) {
93
- case TableAccessRead :
94
- SMP_RDLOCK (table );
95
- break ;
96
- case TableAccessWrite :
97
- SMP_WRLOCK (table );
98
- break ;
99
- default :
100
- break ;
101
- }
102
- ret = table ;
103
- break ;
104
- }
89
+ uint64_t ref = 0 ;
90
+ term name = term_invalid_term ();
91
+ bool is_atom = term_is_atom (name_or_ref );
92
+ if (is_atom ) {
93
+ name = name_or_ref ;
94
+ } else {
95
+ ref = term_to_ref_ticks (name_or_ref );
105
96
}
106
- synclist_unlock (& ets -> ets_tables );
107
- return ret ;
108
- }
109
97
110
- static struct EtsTable * ets_get_table_by_name (struct Ets * ets , term name , TableAccessType access_type )
111
- {
98
+ struct EtsTable * ret = NULL ;
112
99
struct ListHead * ets_tables_list = synclist_rdlock (& ets -> ets_tables );
113
100
struct ListHead * item ;
114
- struct EtsTable * ret = NULL ;
115
101
LIST_FOR_EACH (item , ets_tables_list ) {
116
102
struct EtsTable * table = GET_LIST_ENTRY (item , struct EtsTable , head );
117
- if (table -> is_named && table -> name == name ) {
118
- switch (access_type ) {
119
- case TableAccessRead :
120
- SMP_RDLOCK (table );
121
- break ;
122
- case TableAccessWrite :
123
- SMP_WRLOCK (table );
124
- break ;
125
- default :
126
- break ;
103
+ bool found = is_atom ? table -> is_named && table -> name == name : table -> ref_ticks == ref ;
104
+ if (found ) {
105
+ bool is_owner = table -> owner_process_id == process_id ;
106
+ bool is_non_private = table -> access_type != EtsAccessPrivate ;
107
+ bool is_public = table -> access_type == EtsAccessPublic ;
108
+
109
+ bool can_read = requested_access_type == TableAccessRead && (is_non_private || is_owner );
110
+ bool can_write = requested_access_type == TableAccessWrite && (is_public || is_owner );
111
+ bool access_none = requested_access_type == TableAccessNone ;
112
+ if (can_read ) {
113
+ SMP_RDLOCK (table );
114
+ ret = table ;
115
+ } else if (can_write ) {
116
+ SMP_WRLOCK (table );
117
+ ret = table ;
118
+ } else if (access_none ) {
119
+ ret = table ;
127
120
}
128
- ret = table ;
129
121
break ;
130
122
}
131
123
}
@@ -147,7 +139,7 @@ void ets_destroy(struct Ets *ets, GlobalContext *global)
147
139
EtsErrorCode ets_create_table_maybe_gc (term name , bool is_named , EtsTableType table_type , EtsAccessType access_type , size_t keypos , term * ret , Context * ctx )
148
140
{
149
141
if (is_named ) {
150
- struct EtsTable * ets_table = ets_get_table_by_name (& ctx -> global -> ets , name , TableAccessNone );
142
+ struct EtsTable * ets_table = ets_acquire_table (& ctx -> global -> ets , ETS_ANY_PROCESS , name , TableAccessNone );
151
143
if (ets_table != NULL ) {
152
144
return EtsTableNameInUse ;
153
145
}
@@ -255,10 +247,6 @@ static void ets_delete_all_tables(struct Ets *ets, GlobalContext *global)
255
247
256
248
static EtsErrorCode ets_table_insert (struct EtsTable * ets_table , term entry , Context * ctx )
257
249
{
258
- if (ets_table -> access_type != EtsAccessPublic && ets_table -> owner_process_id != ctx -> process_id ) {
259
- return EtsPermissionDenied ;
260
- }
261
-
262
250
size_t keypos = ets_table -> keypos ;
263
251
264
252
if ((size_t ) term_get_tuple_arity (entry ) < keypos + 1 ) {
@@ -270,7 +258,7 @@ static EtsErrorCode ets_table_insert(struct EtsTable *ets_table, term entry, Con
270
258
return EtsAllocationFailure ;
271
259
}
272
260
273
- EtsHashtableErrorCode res = ets_hashtable_insert (ets_table -> hashtable , new_node , EtsHashtableAllowOverwrite , ctx -> global );
261
+ EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , new_node , EtsHashtableAllowOverwrite , ctx -> global );
274
262
if (UNLIKELY (res != EtsHashtableOk )) {
275
263
return EtsAllocationFailure ;
276
264
}
@@ -280,10 +268,6 @@ static EtsErrorCode ets_table_insert(struct EtsTable *ets_table, term entry, Con
280
268
281
269
static EtsErrorCode ets_table_insert_list (struct EtsTable * ets_table , term list , Context * ctx )
282
270
{
283
- if (ets_table -> access_type != EtsAccessPublic && ets_table -> owner_process_id != ctx -> process_id ) {
284
- return EtsPermissionDenied ;
285
- }
286
-
287
271
term iter = list ;
288
272
size_t size = 0 ;
289
273
@@ -318,8 +302,7 @@ static EtsErrorCode ets_table_insert_list(struct EtsTable *ets_table, term list,
318
302
}
319
303
320
304
for (size_t i = 0 ; i < size ; ++ i ) {
321
-
322
- EtsHashtableErrorCode res = ets_hashtable_insert (ets_table -> hashtable , nodes [i ], EtsHashtableAllowOverwrite , ctx -> global );
305
+ EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , nodes [i ], EtsHashtableAllowOverwrite , ctx -> global );
323
306
assert (res == EtsHashtableOk );
324
307
}
325
308
@@ -329,9 +312,9 @@ static EtsErrorCode ets_table_insert_list(struct EtsTable *ets_table, term list,
329
312
330
313
EtsErrorCode ets_insert (term name_or_ref , term entry , Context * ctx )
331
314
{
332
- 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 );
333
- if (ets_table == NULL ) {
334
- return EtsTableNotFound ;
315
+ struct EtsTable * ets_table = ets_acquire_table ( & ctx -> global -> ets , ctx -> process_id , name_or_ref , TableAccessWrite );
316
+ if (IS_NULL_PTR ( ets_table ) ) {
317
+ return EtsBadAccess ;
335
318
}
336
319
337
320
EtsErrorCode result ;
@@ -350,10 +333,6 @@ EtsErrorCode ets_insert(term name_or_ref, term entry, Context *ctx)
350
333
351
334
static EtsErrorCode ets_table_lookup_maybe_gc (struct EtsTable * ets_table , term key , term * ret , Context * ctx , int num_roots , term * roots )
352
335
{
353
- if (ets_table -> access_type == EtsAccessPrivate && ets_table -> owner_process_id != ctx -> process_id ) {
354
- return EtsPermissionDenied ;
355
- }
356
-
357
336
term res = ets_hashtable_lookup (ets_table -> hashtable , key , ets_table -> keypos , ctx -> global );
358
337
359
338
if (term_is_nil (res )) {
@@ -374,9 +353,9 @@ static EtsErrorCode ets_table_lookup_maybe_gc(struct EtsTable *ets_table, term k
374
353
375
354
EtsErrorCode ets_lookup_maybe_gc (term name_or_ref , term key , term * ret , Context * ctx )
376
355
{
377
- 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 );
378
- if (ets_table == NULL ) {
379
- return EtsTableNotFound ;
356
+ struct EtsTable * ets_table = ets_acquire_table ( & ctx -> global -> ets , ctx -> process_id , name_or_ref , TableAccessRead );
357
+ if (IS_NULL_PTR ( ets_table ) ) {
358
+ return EtsBadAccess ;
380
359
}
381
360
382
361
EtsErrorCode result = ets_table_lookup_maybe_gc (ets_table , key , ret , ctx , 0 , NULL );
@@ -391,14 +370,9 @@ EtsErrorCode ets_lookup_element_maybe_gc(term name_or_ref, term key, size_t pos,
391
370
return EtsBadPosition ;
392
371
}
393
372
394
- 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 );
395
- if (ets_table == NULL ) {
396
- return EtsTableNotFound ;
397
- }
398
-
399
- if (ets_table -> access_type == EtsAccessPrivate && ets_table -> owner_process_id != ctx -> process_id ) {
400
- SMP_UNLOCK (ets_table );
401
- return EtsPermissionDenied ;
373
+ struct EtsTable * ets_table = ets_acquire_table (& ctx -> global -> ets , ctx -> process_id , name_or_ref , TableAccessRead );
374
+ if (IS_NULL_PTR (ets_table )) {
375
+ return EtsBadAccess ;
402
376
}
403
377
404
378
term entry = ets_hashtable_lookup (ets_table -> hashtable , key , ets_table -> keypos , ctx -> global );
@@ -426,29 +400,11 @@ EtsErrorCode ets_lookup_element_maybe_gc(term name_or_ref, term key, size_t pos,
426
400
return EtsOk ;
427
401
}
428
402
429
- static EtsErrorCode ets_table_delete (struct EtsTable * ets_table , term key , term * ret , Context * ctx )
430
- {
431
- if (ets_table -> access_type != EtsAccessPublic && ets_table -> owner_process_id != ctx -> process_id ) {
432
- return EtsPermissionDenied ;
433
- }
434
-
435
- bool _res = ets_hashtable_remove (ets_table -> hashtable , key , ets_table -> keypos , ctx -> global );
436
- UNUSED (_res );
437
-
438
- * ret = TRUE_ATOM ;
439
- return EtsOk ;
440
- }
441
-
442
403
EtsErrorCode ets_drop_table (term name_or_ref , term * ret , Context * ctx )
443
404
{
444
- struct EtsTable * ets_table = term_is_atom (name_or_ref )
445
- ? ets_get_table_by_name (& ctx -> global -> ets , name_or_ref , TableAccessWrite )
446
- : ets_get_table_by_ref (& ctx -> global -> ets , term_to_ref_ticks (name_or_ref ), TableAccessWrite );
405
+ struct EtsTable * ets_table = ets_acquire_table (& ctx -> global -> ets , ctx -> process_id , name_or_ref , TableAccessWrite );
447
406
if (IS_NULL_PTR (ets_table )) {
448
- return EtsTableNotFound ;
449
- }
450
- if (ets_table -> access_type != EtsAccessPublic && ets_table -> owner_process_id != ctx -> process_id ) {
451
- return EtsPermissionDenied ;
407
+ return EtsBadAccess ;
452
408
}
453
409
454
410
struct ListHead * ets_tables_list = synclist_wrlock (& ctx -> global -> ets .ets_tables );
@@ -464,17 +420,17 @@ EtsErrorCode ets_drop_table(term name_or_ref, term *ret, Context *ctx)
464
420
465
421
EtsErrorCode ets_delete (term name_or_ref , term key , term * ret , Context * ctx )
466
422
{
467
- struct EtsTable * ets_table = term_is_atom (name_or_ref )
468
- ? ets_get_table_by_name (& ctx -> global -> ets , name_or_ref , TableAccessRead )
469
- : ets_get_table_by_ref (& ctx -> global -> ets , term_to_ref_ticks (name_or_ref ), TableAccessRead );
423
+ struct EtsTable * ets_table = ets_acquire_table (& ctx -> global -> ets , ctx -> process_id , name_or_ref , TableAccessWrite );
470
424
if (IS_NULL_PTR (ets_table )) {
471
- return EtsTableNotFound ;
425
+ return EtsBadAccess ;
472
426
}
473
427
474
- EtsErrorCode res = ets_table_delete (ets_table , key , ret , ctx );
475
-
428
+ bool _found = ets_hashtable_remove (ets_table -> hashtable , key , ets_table -> keypos , ctx -> global );
429
+ UNUSED ( _found );
476
430
SMP_UNLOCK (ets_table );
477
- return res ;
431
+
432
+ * ret = TRUE_ATOM ;
433
+ return EtsOk ;
478
434
}
479
435
480
436
static bool operation_to_tuple4 (term operation , size_t default_pos , term * position , term * increment , term * threshold , term * set_value )
@@ -524,11 +480,9 @@ static bool operation_to_tuple4(term operation, size_t default_pos, term *positi
524
480
525
481
EtsErrorCode ets_update_counter_maybe_gc (term ref , term key , term operation , term default_value , term * ret , Context * ctx )
526
482
{
527
- struct EtsTable * ets_table = term_is_atom (ref )
528
- ? ets_get_table_by_name (& ctx -> global -> ets , ref , TableAccessWrite )
529
- : ets_get_table_by_ref (& ctx -> global -> ets , term_to_ref_ticks (ref ), TableAccessWrite );
483
+ struct EtsTable * ets_table = ets_acquire_table (& ctx -> global -> ets , ctx -> process_id , ref , TableAccessWrite );
530
484
if (IS_NULL_PTR (ets_table )) {
531
- return EtsTableNotFound ;
485
+ return EtsBadAccess ;
532
486
}
533
487
534
488
// do not use an invalid term as a root
@@ -588,7 +542,7 @@ EtsErrorCode ets_update_counter_maybe_gc(term ref, term key, term operation, ter
588
542
avm_int_t elem_value ;
589
543
if (BUILTIN_ADD_OVERFLOW_INT (increment , term_to_int (elem ), & elem_value )) {
590
544
SMP_UNLOCK (ets_table );
591
- return EtsOverlfow ;
545
+ return EtsOverflow ;
592
546
}
593
547
if (!term_is_invalid_term (threshold_term ) && !term_is_invalid_term (set_value_term )) {
594
548
avm_int_t threshold = term_to_int (threshold_term );
0 commit comments