#ifndef __LKDHASH_H__ #define __LKDHASH_H__ /** * \file * * Macros to implement a hashtable protected by a rwlock. * * With the exception of \c DEFINE_LKDHASH and \c DEFINE_INITIALIZED_LKDHASH, * these macros all use the pthreads function table in glvnd_pthread.h, so you * have to call \c glvndSetupPthreads before using them. */ #include "glvnd_pthread.h" #include "uthash.h" /* * Macros for defining a "locked hash": a hashtable protected by a lock. */ #define DEFINE_LKDHASH(_hashtype, _hashname) \ struct { \ _hashtype *hash; \ glvnd_rwlock_t lock; \ } _hashname #define DEFINE_INITIALIZED_LKDHASH(_hashtype, _hashname) \ struct { \ _hashtype *hash; \ glvnd_rwlock_t lock; \ } _hashname = { NULL, GLVND_RWLOCK_INITIALIZER } #define LKDHASH_INIT(_lockedhash) do { \ (_lockedhash).hash = NULL; \ __glvndPthreadFuncs.rwlock_init(&(_lockedhash).lock, NULL); \ } while (0) /* * Macros for locking/unlocking the locked hash. */ #define LKDHASH_RDLOCK(_lockedhash) \ __glvndPthreadFuncs.rwlock_rdlock(&(_lockedhash).lock) #define LKDHASH_WRLOCK(_lockedhash) \ __glvndPthreadFuncs.rwlock_wrlock(&(_lockedhash).lock) #define LKDHASH_UNLOCK(_lockedhash) \ __glvndPthreadFuncs.rwlock_unlock(&(_lockedhash).lock) /* * Converts a locked hash into a hash suitable for use with uthash. */ #define _LH(_lockedhash) ((_lockedhash).hash) #define LKDHASH_TEARDOWN_2(_lockedhash, _param, _cur, _tmp, _cleanup) do { \ LKDHASH_WRLOCK(_lockedhash); \ HASH_ITER(hh, _LH( _lockedhash), _cur, _tmp) { \ HASH_DEL(_LH(_lockedhash), _cur); \ if (_cleanup) { \ _cleanup(_param, _cur); \ } \ free(_cur); \ } \ assert(!_LH(_lockedhash)); \ LKDHASH_UNLOCK(_lockedhash); \ } while (0) /*! * Macro for deleting all entries in a locked hash, as well as the protecting * lock. Assumes that hash entries have been allocated using malloc(3) or * similar and are safe to pass into free(3). * * _ht indicates the type of the hash table to use, and _lh indicates the * hash table variable. * * _cleanup is a callback function which takes (_void *, _ht *) as arguments, * or NULL. * * _param is an extra parmeter to pass into the callback function of type * (void *). * * _reset indicates whether the lock needs to be re-initialized (for fork * handling). */ #define LKDHASH_TEARDOWN(_ht, _lh, _cleanup, _param, _reset) do { \ _ht *cur ## _ht, *tmp ## _ht; \ typedef void (*pfnCleanup ## _ht)(void *p, _ht *h); \ pfnCleanup ## _ht pCleanup ## _ht = _cleanup; \ LKDHASH_TEARDOWN_2(_lh, _param, cur ## _ht, \ tmp ## _ht, pCleanup ## _ht); \ if (_reset) { \ __glvndPthreadFuncs.rwlock_init(&(_lh).lock, NULL); \ } else { \ __glvndPthreadFuncs.rwlock_destroy(&(_lh).lock); \ } \ } while (0) #endif