예제 #1
0
/*! \brief Unit runnable. */
int runnable(struct dthread_t *thread)
{
	for (int i = 0; i < _runnable_cycles; ++i) {

		// Increase counter
		pthread_mutex_lock(&_runnable_mx);
		++_runnable_i;
		pthread_mutex_unlock(&_runnable_mx);

		// Cancellation point
		if (dt_is_cancelled(thread)) {
			break;
		}

		// Yield
		sched_yield();
	}

	return 0;
}
예제 #2
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;
}
예제 #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
파일: tcp-handler.c 프로젝트: idtek/knot
int tcp_master(dthread_t *thread)
{
	if (!thread || !thread->data) {
		return KNOT_EINVAL;
	}

	iohandler_t *handler = (iohandler_t *)thread->data;
	unsigned *iostate = &handler->thread_state[dt_get_id(thread)];

	int ret = KNOT_EOK;
	ref_t *ref = NULL;
	tcp_context_t tcp;
	memset(&tcp, 0, sizeof(tcp_context_t));

	/* Create big enough memory cushion. */
	knot_mm_t mm;
	mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);

	/* Create TCP answering context. */
	tcp.server = handler->server;
	tcp.thread_id = handler->thread_id[dt_get_id(thread)];
	tcp.overlay.mm = &mm;

	/* Prepare structures for bound sockets. */
	conf_val_t val = conf_get(conf(), C_SRV, C_LISTEN);
	fdset_init(&tcp.set, conf_val_count(&val) + CONF_XFERS);

	/* Create iovec abstraction. */
	for (unsigned i = 0; i < 2; ++i) {
		tcp.iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE;
		tcp.iov[i].iov_base = malloc(tcp.iov[i].iov_len);
		if (tcp.iov[i].iov_base == NULL) {
			ret = KNOT_ENOMEM;
			goto finish;
		}
	}

	/* Initialize sweep interval. */
	timev_t next_sweep = {0};
	time_now(&next_sweep);
	next_sweep.tv_sec += TCP_SWEEP_INTERVAL;

	for(;;) {

		/* Check handler state. */
		if (unlikely(*iostate & ServerReload)) {
			*iostate &= ~ServerReload;

			/* Cancel client connections. */
			for (unsigned i = tcp.client_threshold; i < tcp.set.n; ++i) {
				close(tcp.set.pfd[i].fd);
			}

			ref_release(ref);
			ref = server_set_ifaces(handler->server, &tcp.set, IO_TCP, tcp.thread_id);
			if (tcp.set.n == 0) {
				break; /* Terminate on zero interfaces. */
			}

			tcp.client_threshold = tcp.set.n;
		}

		/* Check for cancellation. */
		if (dt_is_cancelled(thread)) {
			break;
		}

		/* Serve client requests. */
		tcp_wait_for_events(&tcp);

		/* Sweep inactive clients. */
		if (tcp.last_poll_time.tv_sec >= next_sweep.tv_sec) {
			fdset_sweep(&tcp.set, &tcp_sweep, NULL);
			time_now(&next_sweep);
			next_sweep.tv_sec += TCP_SWEEP_INTERVAL;
		}
	}

finish:
	free(tcp.iov[0].iov_base);
	free(tcp.iov[1].iov_base);
	mp_delete(mm.ctx);
	fdset_clear(&tcp.set);
	ref_release(ref);

	return ret;
}