Пример #1
0
Файл: obj.c Проект: jxy859/nvml
/*
 * pmemobj_root_construct -- returns root object
 */
PMEMoid pmemobj_root_construct(PMEMobjpool *pop, size_t size,
	void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg)
{
	LOG(3, "pop %p size %zu constructor %p args %p", pop, size, constructor,
		arg);

	if (size > PMEMOBJ_MAX_ALLOC_SIZE) {
		ERR("requested size too large");
		errno = ENOMEM;
		return OID_NULL;
	}

	PMEMoid root;

	pmemobj_mutex_lock(pop, &pop->rootlock);
	if (pop->store->root.head.pe_first.off == 0)
		/* root object list is empty */
		obj_alloc_root(pop, pop->store, size, constructor, arg);
	else {
		size_t old_size = pmemobj_root_size(pop);
		if (size > old_size)
			if (obj_realloc_root(pop, pop->store, size, old_size,
				constructor, arg)) {
				pmemobj_mutex_unlock(pop, &pop->rootlock);
				LOG(2, "obj_realloc_root failed");
				return OID_NULL;
			}
	}
	root = pop->store->root.head.pe_first;
	pmemobj_mutex_unlock(pop, &pop->rootlock);
	return root;
}
Пример #2
0
		/**
		 * Unlocks a previously locked mutex.
		 *
		 * Unlocking a mutex that has not been locked by the current
		 * thread results in undefined behavior. Unlocking a mutex that
		 * has not been lock also results in undefined behavior.
		 *
		 * @throw lock_error when an error occurs, this includes all
		 * system related errors with the underlying implementation of
		 * the mutex.
		 */
		void unlock()
		{
			PMEMobjpool *pop = pmemobj_pool_by_ptr(this);
			if (int ret = pmemobj_mutex_unlock(pop, &this->plock))
				throw lock_error(ret, std::system_category(),
						"Failed to unlock a mutex.");
		}
Пример #3
0
/*
 * list_mutexes_lock -- (internal) grab one or two locks in ascending
 * address order
 */
static inline int
list_mutexes_lock(PMEMobjpool *pop,
	struct list_head *head1, struct list_head *head2)
{
	ASSERTne(head1, NULL);

	if (!head2 || head1 == head2)
		return pmemobj_mutex_lock(pop, &head1->lock);

	PMEMmutex *lock1;
	PMEMmutex *lock2;
	if ((uintptr_t)&head1->lock < (uintptr_t)&head2->lock) {
		lock1 = &head1->lock;
		lock2 = &head2->lock;
	} else {
		lock1 = &head2->lock;
		lock2 = &head1->lock;
	}

	int ret;
	if ((ret = pmemobj_mutex_lock(pop, lock1)))
		goto err;
	if ((ret = pmemobj_mutex_lock(pop, lock2)))
		goto err_unlock;

	return 0;

err_unlock:
	pmemobj_mutex_unlock(pop, lock1);
err:
	return ret;
}
Пример #4
0
/*
 * timed_check_worker -- (internal) check consistency with mutex
 */
static void *
timed_check_worker(void *arg)
{
	for (unsigned run = 0; run < WORKER_RUNS; run++) {

		int mutex_id = (int)(uintptr_t)arg % 2;
		PMEMmutex *mtx = mutex_id == LOCKED_MUTEX ?
				&Test_obj->mutex_locked : &Test_obj->mutex;

		struct timespec t1, t2, t_diff, abs_time;
		os_clock_gettime(CLOCK_REALTIME, &t1);
		abs_time = t1;
		abs_time.tv_nsec += TIMEOUT;
		if (abs_time.tv_nsec >= NANO_PER_ONE) {
			abs_time.tv_sec += abs_time.tv_nsec / NANO_PER_ONE;
			abs_time.tv_nsec %= NANO_PER_ONE;
		}

		int ret = pmemobj_mutex_timedlock(&Mock_pop, mtx, &abs_time);

		os_clock_gettime(CLOCK_REALTIME, &t2);

		if (mutex_id == LOCKED_MUTEX) {
			UT_ASSERTeq(ret, ETIMEDOUT);
			t_diff.tv_sec = t2.tv_sec - t1.tv_sec;
			t_diff.tv_nsec = t2.tv_nsec - t1.tv_nsec;

			if (t_diff.tv_nsec < 0) {
				--t_diff.tv_sec;
				t_diff.tv_nsec += NANO_PER_ONE;
			}
			UT_ASSERT(t_diff.tv_sec * NANO_PER_ONE +
					t_diff.tv_nsec >= TIMEOUT);

			return NULL;
		}

		if (ret == 0) {
			UT_ASSERTne(mutex_id, LOCKED_MUTEX);
			pmemobj_mutex_unlock(&Mock_pop, mtx);
		} else if (ret == ETIMEDOUT) {
			t_diff.tv_sec = t2.tv_sec - t1.tv_sec;
			t_diff.tv_nsec = t2.tv_nsec - t1.tv_nsec;

			if (t_diff.tv_nsec < 0) {
				--t_diff.tv_sec;
				t_diff.tv_nsec += NANO_PER_ONE;
			}
			UT_ASSERT(t_diff.tv_sec * NANO_PER_ONE +
					t_diff.tv_nsec >= TIMEOUT);
		} else {
			errno = ret;
			UT_ERR("!pmemobj_mutex_timedlock");
		}
	}

	return NULL;
}
Пример #5
0
/*
 * mutex_write_worker -- (internal) write data with mutex
 */
static void *
mutex_write_worker(void *arg)
{
	for (unsigned run = 0; run < WORKER_RUNS; run++) {
		if (pmemobj_mutex_lock(&Mock_pop, &Test_obj->mutex)) {
			UT_ERR("pmemobj_mutex_lock");
			return NULL;
		}

		memset(Test_obj->data, (int)(uintptr_t)arg, DATA_SIZE);
		if (pmemobj_mutex_unlock(&Mock_pop, &Test_obj->mutex))
			UT_ERR("pmemobj_mutex_unlock");
	}

	return NULL;
}
Пример #6
0
/*
 * cond_write_worker -- (internal) write data with cond variable
 */
static void *
cond_write_worker(void *arg)
{
	for (unsigned run = 0; run < WORKER_RUNS; run++) {
		if (pmemobj_mutex_lock(&Mock_pop, &Test_obj->mutex))
			return NULL;

		memset(Test_obj->data, (int)(uintptr_t)arg, DATA_SIZE);
		Test_obj->check_data = 1;
		if (pmemobj_cond_signal(&Mock_pop, &Test_obj->cond))
			UT_ERR("pmemobj_cond_signal");
		pmemobj_mutex_unlock(&Mock_pop, &Test_obj->mutex);
	}

	return NULL;
}
Пример #7
0
/*
 * mutex_check_worker -- (internal) check consistency with mutex
 */
static void *
mutex_check_worker(void *arg)
{
	for (unsigned run = 0; run < WORKER_RUNS; run++) {
		if (pmemobj_mutex_lock(&Mock_pop, &Test_obj->mutex)) {
			UT_ERR("pmemobj_mutex_lock");
			return NULL;
		}
		uint8_t val = Test_obj->data[0];
		for (int i = 1; i < DATA_SIZE; i++)
			UT_ASSERTeq(Test_obj->data[i], val);

		memset(Test_obj->data, 0, DATA_SIZE);
		if (pmemobj_mutex_unlock(&Mock_pop, &Test_obj->mutex))
			UT_ERR("pmemobj_mutex_unlock");
	}

	return NULL;
}
Пример #8
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "obj_sync");
	util_init();

	if (argc < 4)
		FATAL_USAGE();

	worker writer;
	worker checker;

	char test_type = argv[1][0];
	switch (test_type) {
		case 'm':
			writer = mutex_write_worker;
			checker = mutex_check_worker;
			break;
		case 'r':
			writer = rwlock_write_worker;
			checker = rwlock_check_worker;
			break;
		case 'c':
			writer = cond_write_worker;
			checker = cond_check_worker;
			break;
		case 't':
			writer = timed_write_worker;
			checker = timed_check_worker;
			break;
		default:
			FATAL_USAGE();

	}

	unsigned long num_threads = strtoul(argv[2], NULL, 10);
	if (num_threads > MAX_THREAD_NUM)
		UT_FATAL("Do not use more than %d threads.\n", MAX_THREAD_NUM);

	unsigned long opens = strtoul(argv[3], NULL, 10);
	if (opens > MAX_OPENS)
		UT_FATAL("Do not use more than %d runs.\n", MAX_OPENS);

	os_thread_t *write_threads
		= (os_thread_t *)MALLOC(num_threads * sizeof(os_thread_t));
	os_thread_t *check_threads
		= (os_thread_t *)MALLOC(num_threads * sizeof(os_thread_t));

	/* first pool open */
	mock_open_pool(&Mock_pop);
	Mock_pop.p_ops.persist = obj_sync_persist;
	Mock_pop.p_ops.base = &Mock_pop;
	Test_obj = (struct mock_obj *)MALLOC(sizeof(struct mock_obj));
	/* zero-initialize the test object */
	pmemobj_mutex_zero(&Mock_pop, &Test_obj->mutex);
	pmemobj_mutex_zero(&Mock_pop, &Test_obj->mutex_locked);
	pmemobj_cond_zero(&Mock_pop, &Test_obj->cond);
	pmemobj_rwlock_zero(&Mock_pop, &Test_obj->rwlock);
	Test_obj->check_data = 0;
	memset(&Test_obj->data, 0, DATA_SIZE);

	for (unsigned long run = 0; run < opens; run++) {
		if (test_type == 't') {
			pmemobj_mutex_lock(&Mock_pop,
					&Test_obj->mutex_locked);
		}

		for (unsigned i = 0; i < num_threads; i++) {
			PTHREAD_CREATE(&write_threads[i], NULL, writer,
				(void *)(uintptr_t)i);
			PTHREAD_CREATE(&check_threads[i], NULL, checker,
				(void *)(uintptr_t)i);
		}
		for (unsigned i = 0; i < num_threads; i++) {
			PTHREAD_JOIN(&write_threads[i], NULL);
			PTHREAD_JOIN(&check_threads[i], NULL);
		}

		if (test_type == 't') {
			pmemobj_mutex_unlock(&Mock_pop,
					&Test_obj->mutex_locked);
		}
		/* up the run_id counter and cleanup */
		mock_open_pool(&Mock_pop);
		cleanup(test_type);
	}

	FREE(check_threads);
	FREE(write_threads);
	FREE(Test_obj);
	DONE(NULL);
}