diff --git a/src/c/hash.d b/src/c/hash.d index fda846cf2..4c5c00c16 100644 --- a/src/c/hash.d +++ b/src/c/hash.d @@ -653,7 +653,42 @@ _ecl_remhash_weak(cl_object key, cl_object hashtable) return 0; } } +#endif +/* SYNCHRONIZED HASH TABLES */ +#ifdef ECL_THREADS +static cl_object +_ecl_sethash_sync(cl_object key, cl_object hashtable, cl_object value) +{ + cl_object output = ECL_NIL; + cl_object sync_lock = hashtable->hash.sync_lock; + mp_get_rwlock_write_wait(sync_lock); + output = hashtable->hash.set_unsafe(key, hashtable, value); + mp_giveup_rwlock_write(sync_lock); + return output; +} + +static cl_object +_ecl_gethash_sync(cl_object key, cl_object hashtable, cl_object def) +{ + cl_object output = ECL_NIL; + cl_object sync_lock = hashtable->hash.sync_lock; + mp_get_rwlock_read_wait(sync_lock); + output = hashtable->hash.get_unsafe(key, hashtable, def); + mp_giveup_rwlock_read(sync_lock); + return output; +} + +static bool +_ecl_remhash_sync(cl_object key, cl_object hashtable) +{ + bool output = 0; + cl_object sync_lock = hashtable->hash.sync_lock; + mp_get_rwlock_write_wait(sync_lock); + output = hashtable->hash.rem_unsafe(key, hashtable); + mp_giveup_rwlock_write(sync_lock); + return output; +} #endif /* @@ -775,6 +810,22 @@ ecl_extend_hashtable(cl_object hashtable) hash->hash.rem = _ecl_remhash_weak; } #endif + + if (!Null(synchronized)) { +#ifdef ECL_THREADS + hash->hash.sync_lock = ecl_make_rwlock(ECL_NIL); + hash->hash.get_unsafe = hash->hash.get; + hash->hash.set_unsafe = hash->hash.set; + hash->hash.rem_unsafe = hash->hash.rem; + hash->hash.get = _ecl_gethash_sync; + hash->hash.set = _ecl_sethash_sync; + hash->hash.rem = _ecl_remhash_sync; +#else + /* for hash-table-synchronized-p predicate */ + hash->hash.sync_lock = ECL_T; +#endif + } + @(return hash); } @) @@ -924,11 +975,10 @@ si_hash_table_weakness(cl_object ht) cl_object si_hash_table_synchronized_p(cl_object ht) { -#if 0 - if (ht->hash.sync) { + + if (!Null(ht->hash.sync_lock)) { return ECL_T; } -#endif return ECL_NIL; } diff --git a/src/h/object.h b/src/h/object.h index f2404613e..ebc31e816 100644 --- a/src/h/object.h +++ b/src/h/object.h @@ -369,6 +369,7 @@ struct ecl_hashtable_entry { /* hash table entry */ struct ecl_hashtable { /* hash table header */ _ECL_HDR2(test,weak); struct ecl_hashtable_entry *data; /* pointer to the hash table */ + cl_object sync_lock; /* synchronization lock */ cl_index entries; /* number of entries */ cl_index size; /* hash table size */ cl_index limit; /* hash table threshold (integer value) */ @@ -378,6 +379,11 @@ struct ecl_hashtable { /* hash table header */ cl_object (*get)(cl_object, cl_object, cl_object); cl_object (*set)(cl_object, cl_object, cl_object); bool (*rem)(cl_object, cl_object); + /* Unsafe variants are used to store the real accessors when + the synchronized variant is bound to get/set/rem. */ + cl_object (*get_unsafe)(cl_object, cl_object, cl_object); + cl_object (*set_unsafe)(cl_object, cl_object, cl_object); + bool (*rem_unsafe)(cl_object, cl_object); }; typedef enum { /* array element type */ diff --git a/src/tests/normal-tests/hash-tables.lsp b/src/tests/normal-tests/hash-tables.lsp index 2e13ee352..93e6ba4e2 100644 --- a/src/tests/normal-tests/hash-tables.lsp +++ b/src/tests/normal-tests/hash-tables.lsp @@ -64,3 +64,9 @@ (test hash-tables.weak-err (signals simple-type-error (make-hash-table :weakness :whatever))) + + +;;; Synchronization +(test hash-tables.sync + (let ((ht (make-hash-table :synchronized t))) + (is-true (ext:hash-table-synchronized-p ht))))