#include "unittest.h"
#include "libpmemobj.h"
#define LAYOUT_NAME "obj_tx_lock"
#define NUM_LOCKS 2
struct transaction_data {
PMEMmutex mutexes[NUM_LOCKS];
PMEMrwlock rwlocks[NUM_LOCKS];
};
PMEMobjpool *Pop;
#define DO_LOCK(mtx, rwlock)\
pmemobj_tx_lock(TX_PARAM_MUTEX, &(mtx)[0]);\
pmemobj_tx_lock(TX_PARAM_MUTEX, &(mtx)[1]);\
pmemobj_tx_lock(TX_PARAM_RWLOCK, &(rwlock)[0]);\
pmemobj_tx_lock(TX_PARAM_RWLOCK, &(rwlock)[1])
#define IS_UNLOCKED(pop, mtx, rwlock)\
ret = 0;\
ret += pmemobj_mutex_trylock((pop), &(mtx)[0]);\
ret += pmemobj_mutex_trylock((pop), &(mtx)[1]);\
ret += pmemobj_rwlock_trywrlock((pop), &(rwlock)[0]);\
ret += pmemobj_rwlock_trywrlock((pop), &(rwlock)[1]);\
UT_ASSERTeq(ret, 0);\
pmemobj_mutex_unlock((pop), &(mtx)[0]);\
pmemobj_mutex_unlock((pop), &(mtx)[1]);\
pmemobj_rwlock_unlock((pop), &(rwlock)[0]);\
pmemobj_rwlock_unlock((pop), &(rwlock)[1])
#define IS_LOCKED(pop, mtx, rwlock)\
ret = pmemobj_mutex_trylock((pop), &(mtx)[0]);\
UT_ASSERT(ret != 0);\
ret = pmemobj_mutex_trylock((pop), &(mtx)[1]);\
UT_ASSERT(ret != 0);\
ret = pmemobj_rwlock_trywrlock((pop), &(rwlock)[0]);\
UT_ASSERT(ret != 0);\
ret = pmemobj_rwlock_trywrlock((pop), &(rwlock)[1]);\
UT_ASSERT(ret != 0)
static void *
do_tx_add_locks(struct transaction_data *data)
{
int ret;
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
TX_BEGIN(Pop) {
DO_LOCK(data->mutexes, data->rwlocks);
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
return NULL;
}
static void *
do_tx_add_locks_nested(struct transaction_data *data)
{
int ret;
TX_BEGIN(Pop) {
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
TX_BEGIN(Pop) {
DO_LOCK(data->mutexes, data->rwlocks);
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
} TX_END
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
return NULL;
}
static void *
do_tx_add_locks_nested_all(struct transaction_data *data)
{
int ret;
TX_BEGIN(Pop) {
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
DO_LOCK(data->mutexes, data->rwlocks);
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
TX_BEGIN(Pop) {
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
DO_LOCK(data->mutexes, data->rwlocks);
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
} TX_END
IS_LOCKED(Pop, data->mutexes, data->rwlocks);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
IS_UNLOCKED(Pop, data->mutexes, data->rwlocks);
return NULL;
}
int
main(int argc, char *argv[])
{
START(argc, argv, "obj_tx_lock");
if (argc != 2)
UT_FATAL("usage: %s <file>", argv[0]);
if ((Pop = pmemobj_create(argv[1], LAYOUT_NAME,
PMEMOBJ_MIN_POOL, S_IWUSR | S_IRUSR)) == NULL)
UT_FATAL("!pmemobj_create");
PMEMoid root = pmemobj_root(Pop, sizeof(struct transaction_data));
struct transaction_data *test_obj =
(struct transaction_data *)pmemobj_direct(root);
do_tx_add_locks(test_obj);
do_tx_add_locks_nested(test_obj);
do_tx_add_locks_nested_all(test_obj);
pmemobj_close(Pop);
DONE(NULL);
}