hash-table: add synchronization implementation

This commit is contained in:
Daniel Kochmanski 2017-04-28 22:09:12 +02:00
parent c88af87046
commit 57bdf6e989
3 changed files with 65 additions and 3 deletions

View file

@ -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;
}

View file

@ -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 */

View file

@ -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))))