示例#1
0
int dt_stop(dt_unit_t *unit)
{
	// Check unit
	if (unit == 0) {
		return KNOT_EINVAL;
	}

	// Lock unit
	pthread_mutex_lock(&unit->_notify_mx);
	dt_unit_lock(unit);

	// Signalize all threads to stop
	for (int i = 0; i < unit->size; ++i) {

		// Lock thread
		dthread_t *thread = unit->threads[i];
		lock_thread_rw(thread);
		if (thread->state & (ThreadIdle | ThreadActive)) {
			thread->state = ThreadDead | ThreadCancelled;
			dbg_dt("dthreads: [%p] %s: stopping thread\n",
			         thread, __func__);
			dt_signalize(thread, SIGALRM);
		}
		unlock_thread_rw(thread);
	}

	// Unlock unit
	dt_unit_unlock(unit);

	// Broadcast notification
	pthread_cond_broadcast(&unit->_notify);
	pthread_mutex_unlock(&unit->_notify_mx);

	return KNOT_EOK;
}
示例#2
0
int dt_compact(dt_unit_t *unit)
{
	// Check input
	if (unit == 0) {
		return KNOT_EINVAL;
	}

	// Lock unit
	pthread_mutex_lock(&unit->_notify_mx);
	dt_unit_lock(unit);

	// Reclaim all Idle threads
	for (int i = 0; i < unit->size; ++i) {

		// Locked state update
		dthread_t *thread = unit->threads[i];
		lock_thread_rw(thread);
		if (thread->state & (ThreadIdle)) {
			thread->state = ThreadDead | ThreadCancelled;
			dt_signalize(thread, SIGALRM);
		}
		unlock_thread_rw(thread);
	}

	// Notify all threads
	pthread_cond_broadcast(&unit->_notify);
	pthread_mutex_unlock(&unit->_notify_mx);

	// Join all threads
	for (int i = 0; i < unit->size; ++i) {

		// Reclaim all dead threads
		dthread_t *thread = unit->threads[i];
		lock_thread_rw(thread);
		if (thread->state & (ThreadDead)) {
			dbg_dt_verb("dthreads: [%p] %s: reclaiming thread\n",
			            thread, __func__);
			unlock_thread_rw(thread);
			pthread_join(thread->_thr, 0);
			dbg_dt("dthreads: [%p] %s: thread reclaimed\n",
			       thread, __func__);
			lock_thread_rw(thread);
			thread->state = ThreadJoined;
			unlock_thread_rw(thread);
		} else {
			unlock_thread_rw(thread);
		}
	}

	dbg_dt_verb("dthreads: compact: joined all threads\n");

	// Unlock unit
	dt_unit_unlock(unit);

	return KNOT_EOK;
}
示例#3
0
/*! API: run tests. */
static int dt_tests_run(int argc, char *argv[])
{
	// Register service and signal handler
	struct sigaction sa;
	sa.sa_handler = interrupt_handle;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGALRM, &sa, NULL); // Interrupt

	/* Initialize */
	srand(time(NULL));
	struct timeval tv;
	pthread_mutex_init(&_runnable_mx, NULL);

	/* Test 1: Create unit */
	dt_unit_t *unit = dt_test_create(2);
	ok(unit != 0, "dthreads: create unit (optimal size %d)", unit->size);
	skip(unit == 0, DT_TEST_COUNT - 1);

	/* Test 2: Assign a single task. */
	ok(dt_test_single(unit), "dthreads: assign single task");

	/* Test 3: Start tasks. */
	_runnable_i = 0;
	ok(dt_test_start(unit), "dthreads: start single task");

	/* Test 4: Wait for tasks. */
	ok(dt_test_join(unit), "dthreads: join threads");

	/* Test 5: Compare counter. */
	int expected = _runnable_cycles * 1;
	cmp_ok(_runnable_i, "==", expected, "dthreads: result ok");

	/* Test 6: Repurpose threads. */
	_runnable_i = 0;
	ok(dt_test_coherent(unit), "dthreads: repurpose to coherent");

	/* Test 7: Restart threads. */
	ok(dt_test_start(unit), "dthreads: start coherent unit");

	/* Test 8: Repurpose single thread. */
	tv.tv_sec = 0;
	tv.tv_usec = 4000 + rand() % 1000; // 4-5ms
	note("waiting for %dus to let thread do some work ...",
	     tv.tv_usec);
	select(0, 0, 0, 0, &tv);
	ok(dt_test_repurpose(unit, 0), "dthreads: repurpose on-the-fly");

	/* Test 9: Cancel blocking thread. */
	tv.tv_sec = 0;
	tv.tv_usec = (250 + rand() % 500) * 1000; // 250-750ms
	note("waiting for %dms to let thread pretend blocking I/O ...",
	     tv.tv_usec / 1000);
	select(0, 0, 0, 0, &tv);
	ok(dt_test_cancel(unit, 0), "dthreads: cancel blocking thread");

	/* Test 10: Wait for tasks. */
	ok(dt_test_join(unit), "dthreads: join threads");

	/* Test 11: Compare counter. */
	int expected_lo = _runnable_cycles * (unit->size - 1);
	cmp_ok(_runnable_i, ">=", expected_lo,
	       "dthreads: result %d is => %d", _runnable_i, expected_lo);

	/* Test 12: Compare counter #2. */
	/*! \note repurpose could trigger next run of the unit if both finished */
	int expected_hi = _runnable_cycles * (unit->size + unit->size - 1);
	cmp_ok(_runnable_i, "<=", expected_hi,
	       "dthreads: result %d is <= %d", _runnable_i, expected_hi);

	/* Test 13: Reanimate dead threads. */
	ok(dt_test_reanimate(unit), "dthreads: reanimate dead threads");

	/* Test 14: Deinitialize */
	dt_delete(&unit);
	ok(unit == 0, "dthreads: delete unit");
	endskip;

	/* Test 15: Wrong values. */
	unit = dt_create(-1);
	ok(unit == 0, "dthreads: create with negative count");
	unit = dt_create_coherent(dt_optimal_size(), 0, 0);

	/* Test 16: NULL runnable. */
	cmp_ok(dt_start(unit), "==", 0, "dthreads: start with NULL runnable");

	/* Test 17: NULL operations crashing. */
	int op_count = 14;
	int expected_min = op_count * -1;
	// All functions must return -1 at least
	int ret = 0;
	lives_ok( {
		ret += dt_activate(0);              // -1
		ret += dt_cancel(0);                // -1
		ret += dt_compact(0);               // -1
		dt_delete(0);                //
		ret += dt_is_cancelled(0);          // 0
		ret += dt_join(0);                  // -1
		ret += dt_repurpose(0, 0, 0);       // -1
		ret += dt_signalize(0, SIGALRM);    // -1
		ret += dt_start(0);                 // -1
		ret += dt_start_id(0);              // -1
		ret += dt_stop(0);                  // -1
		ret += dt_stop_id(0);               // -1
		ret += dt_unit_lock(0);             // -1
		ret += dt_unit_unlock(0);           // -1
	}, "dthreads: not crashed while executing functions on NULL context");
示例#4
0
/*! API: run tests. */
int main(int argc, char *argv[])
{
	plan(8);

	// Register service and signal handler
	struct sigaction sa;
	sa.sa_handler = interrupt_handle;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGALRM, &sa, NULL); // Interrupt

	/* Initialize */
	srand(time(NULL));
	pthread_mutex_init(&_runnable_mx, NULL);
	pthread_mutex_init(&_destructor_mx, NULL);

	/* Test 1: Create unit */
	dt_unit_t *unit = dt_create(2, &runnable, NULL, NULL);
	ok(unit != NULL, "dthreads: create unit (size %d)", unit->size);
	if (unit == NULL) {
		skip_block(7, "No dthreads unit");
		goto skip_all;
	}

	/* Test 2: Start tasks. */
	_runnable_i = 0;
	ok(dt_start(unit) == 0, "dthreads: start single task");

	/* Test 3: Wait for tasks. */
	ok(dt_join(unit) == 0, "dthreads: join threads");

	/* Test 4: Compare counter. */
	int expected = _runnable_cycles * 2;
	is_int(expected, _runnable_i, "dthreads: result ok");

	/* Test 5: Deinitialize */
	dt_delete(&unit);
	ok(unit == NULL, "dthreads: delete unit");

	/* Test 6: Wrong values. */
	unit = dt_create(-1, NULL, NULL, NULL);
	ok(unit == NULL, "dthreads: create with negative count");

	/* Test 7: NULL operations crashing. */
	int ret = 0;
	ret += dt_activate(0);
	ret += dt_cancel(0);
	ret += dt_compact(0);
	dt_delete(0);
	ret += dt_is_cancelled(0);
	ret += dt_join(0);
	ret += dt_signalize(0, SIGALRM);
	ret += dt_start(0);
	ret += dt_stop(0);
	ret += dt_unit_lock(0);
	ret += dt_unit_unlock(0);
	is_int(-1098, ret, "dthreads: correct values when passed NULL context");

	/* Test 8: Thread destructor. */
	_destructor_data = 0;
	unit = dt_create(2, 0, destruct, 0);
	dt_start(unit);
	dt_stop(unit);
	dt_join(unit);
	is_int(2, _destructor_data, "dthreads: destructor with dt_create_coherent()");
	dt_delete(&unit);

skip_all:

	pthread_mutex_destroy(&_runnable_mx);
	pthread_mutex_destroy(&_destructor_mx);
	return 0;
}