ATF_TC_BODY(all_events, tc) {
	isc_result_t result;
	isc_task_t *task = NULL;
	isc_event_t *event;
	int a = 0, b = 0;
	int i = 0;

	UNUSED(tc);

	counter = 1;

	result = isc_mutex_init(&set_lock);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_test_begin(NULL, ISC_TRUE);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_task_create(taskmgr, 0, &task);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	/* First event */
	event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
				   set, &a, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(a, 0);
	isc_task_send(task, &event);

	event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
				   set, &b, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(b, 0);
	isc_task_send(task, &event);

	while ((a == 0 || b == 0) && i++ < 5000) {
#ifndef ISC_PLATFORM_USETHREADS
		while (isc__taskmgr_ready(taskmgr))
			isc__taskmgr_dispatch(taskmgr);
#endif
		isc_test_nap(1000);
	}

	ATF_CHECK(a != 0);
	ATF_CHECK(b != 0);

	isc_task_destroy(&task);
	ATF_REQUIRE_EQ(task, NULL);

	isc_test_end();
}
static isc_result_t
waitfor(completion_t *completion) {
	int i = 0;
	while (!completion->done && i++ < 5000) {
#ifndef ISC_PLATFORM_USETHREADS
		while (isc__taskmgr_ready(taskmgr))
			isc__taskmgr_dispatch(taskmgr);
#endif
		isc_test_nap(1000);
	}
	if (completion->done)
		return (ISC_R_SUCCESS);
	return (ISC_R_FAILURE);
}
Beispiel #3
0
void
isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
	isc_taskmgr_t *manager;
	isc_task_t *task;
	unsigned int i;

	/*
	 * Destroy '*managerp'.
	 */

	REQUIRE(managerp != NULL);
	manager = *managerp;
	REQUIRE(VALID_MANAGER(manager));

#ifndef ISC_PLATFORM_USETHREADS
	UNUSED(i);

	if (manager->refs > 1) {
		manager->refs--;
		*managerp = NULL;
		return;
	}
#endif /* ISC_PLATFORM_USETHREADS */

	XTHREADTRACE("isc_taskmgr_destroy");
	/*
	 * Only one non-worker thread may ever call this routine.
	 * If a worker thread wants to initiate shutdown of the
	 * task manager, it should ask some non-worker thread to call
	 * isc_taskmgr_destroy(), e.g. by signalling a condition variable
	 * that the startup thread is sleeping on.
	 */

	/*
	 * Unlike elsewhere, we're going to hold this lock a long time.
	 * We need to do so, because otherwise the list of tasks could
	 * change while we were traversing it.
	 *
	 * This is also the only function where we will hold both the
	 * task manager lock and a task lock at the same time.
	 */

	LOCK(&manager->lock);

	/*
	 * Make sure we only get called once.
	 */
	INSIST(!manager->exiting);
	manager->exiting = ISC_TRUE;

	/*
	 * Post shutdown event(s) to every task (if they haven't already been
	 * posted).
	 */
	for (task = HEAD(manager->tasks);
	     task != NULL;
	     task = NEXT(task, link)) {
		LOCK(&task->lock);
		if (task_shutdown(task))
			ENQUEUE(manager->ready_tasks, task, ready_link);
		UNLOCK(&task->lock);
	}
#ifdef ISC_PLATFORM_USETHREADS
	/*
	 * Wake up any sleeping workers.  This ensures we get work done if
	 * there's work left to do, and if there are already no tasks left
	 * it will cause the workers to see manager->exiting.
	 */
	BROADCAST(&manager->work_available);
	UNLOCK(&manager->lock);

	/*
	 * Wait for all the worker threads to exit.
	 */
	for (i = 0; i < manager->workers; i++)
		(void)isc_thread_join(manager->threads[i], NULL);
#else /* ISC_PLATFORM_USETHREADS */
	/*
	 * Dispatch the shutdown events.
	 */
	UNLOCK(&manager->lock);
	while (isc__taskmgr_ready())
		(void)isc__taskmgr_dispatch();
	if (!ISC_LIST_EMPTY(manager->tasks))
		isc_mem_printallactive(stderr);
	INSIST(ISC_LIST_EMPTY(manager->tasks));
#endif /* ISC_PLATFORM_USETHREADS */

	manager_free(manager);

	*managerp = NULL;
}
Beispiel #4
0
/*!
 * Event loop for nonthreaded programs.
 */
static isc_result_t
evloop(isc__appctx_t *ctx) {
	isc_result_t result;

	while (!ctx->want_shutdown) {
		int n;
		isc_time_t when, now;
		struct timeval tv, *tvp;
		isc_socketwait_t *swait;
		isc_boolean_t readytasks;
		isc_boolean_t call_timer_dispatch = ISC_FALSE;

		/*
		 * Check the reload (or suspend) case first for exiting the
		 * loop as fast as possible in case:
		 *   - the direct call to isc__taskmgr_dispatch() in
		 *     isc__app_ctxrun() completes all the tasks so far,
		 *   - there is thus currently no active task, and
		 *   - there is a timer event
		 */
		if (ctx->want_reload) {
			ctx->want_reload = ISC_FALSE;
			return (ISC_R_RELOAD);
		}

		readytasks = isc__taskmgr_ready(ctx->taskmgr);
		if (readytasks) {
			tv.tv_sec = 0;
			tv.tv_usec = 0;
			tvp = &tv;
			call_timer_dispatch = ISC_TRUE;
		} else {
			result = isc__timermgr_nextevent(ctx->timermgr, &when);
			if (result != ISC_R_SUCCESS)
				tvp = NULL;
			else {
				isc_uint64_t us;

				TIME_NOW(&now);
				us = isc_time_microdiff(&when, &now);
				if (us == 0)
					call_timer_dispatch = ISC_TRUE;
				tv.tv_sec = us / 1000000;
				tv.tv_usec = us % 1000000;
				tvp = &tv;
			}
		}

		swait = NULL;
		n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait);

		if (n == 0 || call_timer_dispatch) {
			/*
			 * We call isc__timermgr_dispatch() only when
			 * necessary, in order to reduce overhead.  If the
			 * select() call indicates a timeout, we need the
			 * dispatch.  Even if not, if we set the 0-timeout
			 * for the select() call, we need to check the timer
			 * events.  In the 'readytasks' case, there may be no
			 * timeout event actually, but there is no other way
			 * to reduce the overhead.
			 * Note that we do not have to worry about the case
			 * where a new timer is inserted during the select()
			 * call, since this loop only runs in the non-thread
			 * mode.
			 */
			isc__timermgr_dispatch(ctx->timermgr);
		}
		if (n > 0)
			(void)isc__socketmgr_dispatch(ctx->socketmgr, swait);
		(void)isc__taskmgr_dispatch(ctx->taskmgr);
	}
	return (ISC_R_SUCCESS);
}
Beispiel #5
0
/*!
 * Event loop for nonthreaded programs.
 */
static isc_result_t
evloop() {
	isc_result_t result;
	while (!want_shutdown) {
		int n;
		isc_time_t when, now;
		struct timeval tv, *tvp;
		fd_set *readfds, *writefds;
		int maxfd;
		isc_boolean_t readytasks;
		isc_boolean_t call_timer_dispatch = ISC_FALSE;

		readytasks = isc__taskmgr_ready();
		if (readytasks) {
			tv.tv_sec = 0;
			tv.tv_usec = 0;
			tvp = &tv;
			call_timer_dispatch = ISC_TRUE;
		} else {
			result = isc__timermgr_nextevent(&when);
			if (result != ISC_R_SUCCESS)
				tvp = NULL;
			else {
				isc_uint64_t us;

				TIME_NOW(&now);
				us = isc_time_microdiff(&when, &now);
				if (us == 0)
					call_timer_dispatch = ISC_TRUE;
				tv.tv_sec = us / 1000000;
				tv.tv_usec = us % 1000000;
				tvp = &tv;
			}
		}

		isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd);
		n = select(maxfd, readfds, writefds, NULL, tvp);

		if (n == 0 || call_timer_dispatch) {
			/*
			 * We call isc__timermgr_dispatch() only when
			 * necessary, in order to reduce overhead.  If the
			 * select() call indicates a timeout, we need the
			 * dispatch.  Even if not, if we set the 0-timeout 
			 * for the select() call, we need to check the timer
			 * events.  In the 'readytasks' case, there may be no
			 * timeout event actually, but there is no other way
			 * to reduce the overhead.
			 * Note that we do not have to worry about the case
			 * where a new timer is inserted during the select()
			 * call, since this loop only runs in the non-thread
			 * mode.
			 */
			isc__timermgr_dispatch();
		}
		if (n > 0)
			(void)isc__socketmgr_dispatch(readfds, writefds,
						      maxfd);
		(void)isc__taskmgr_dispatch();

		if (want_reload) {
			want_reload = ISC_FALSE;
			return (ISC_R_RELOAD);
		}
	}
	return (ISC_R_SUCCESS);
}
ATF_TC_BODY(privilege_drop, tc) {
	isc_result_t result;
	isc_task_t *task1 = NULL, *task2 = NULL;
	isc_event_t *event;
	int a = -1, b = -1, c = -1, d = -1, e = -1;	/* non valid states */
	int i = 0;

	UNUSED(tc);

	counter = 1;
	result = isc_mutex_init(&set_lock);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_test_begin(NULL, ISC_TRUE);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

#ifdef ISC_PLATFORM_USETHREADS
	/*
	 * Pause the task manager so we can fill up the work queue
	 * without things happening while we do it.
	 */
	isc__taskmgr_pause(taskmgr);
#endif

	result = isc_task_create(taskmgr, 0, &task1);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	isc_task_setname(task1, "privileged", NULL);
	ATF_CHECK(!isc_task_privilege(task1));
	isc_task_setprivilege(task1, ISC_TRUE);
	ATF_CHECK(isc_task_privilege(task1));

	result = isc_task_create(taskmgr, 0, &task2);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	isc_task_setname(task2, "normal", NULL);
	ATF_CHECK(!isc_task_privilege(task2));

	/* First event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set_and_drop, &a, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(a, -1);
	isc_task_send(task1, &event);

	/* Second event: not privileged */
	event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
				   set_and_drop, &b, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(b, -1);
	isc_task_send(task2, &event);

	/* Third event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set_and_drop, &c, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(c, -1);
	isc_task_send(task1, &event);

	/* Fourth event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set_and_drop, &d, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(d, -1);
	isc_task_send(task1, &event);

	/* Fifth event: not privileged */
	event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
				   set_and_drop, &e, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(e, -1);
	isc_task_send(task2, &event);

	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
	isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);

#ifdef ISC_PLATFORM_USETHREADS
	isc__taskmgr_resume(taskmgr);
#endif

	/* We're waiting for all variables to be set. */
	while ((a == -1 || b == -1 || c == -1 || d == -1 || e == -1) &&
	       i++ < 5000) {
#ifndef ISC_PLATFORM_USETHREADS
		while (isc__taskmgr_ready(taskmgr))
			isc__taskmgr_dispatch(taskmgr);
#endif
		isc_test_nap(1000);
	}

	/*
	 * We can't guarantee what order the events fire, but
	 * we do know *exactly one* of the privileged tasks will
	 * have run in privileged mode...
	 */
	ATF_CHECK(a == isc_taskmgrmode_privileged ||
		  c == isc_taskmgrmode_privileged ||
		  d == isc_taskmgrmode_privileged);
	ATF_CHECK(a + c + d == isc_taskmgrmode_privileged);

	/* ...and neither of the non-privileged tasks did... */
	ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal);

	/* ...but all five of them did run. */
	ATF_CHECK_EQ(counter, 6);

	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);

	isc_task_destroy(&task1);
	ATF_REQUIRE_EQ(task1, NULL);
	isc_task_destroy(&task2);
	ATF_REQUIRE_EQ(task2, NULL);

	isc_test_end();
}
ATF_TC_BODY(privileged_events, tc) {
	isc_result_t result;
	isc_task_t *task1 = NULL, *task2 = NULL;
	isc_event_t *event;
	int a = 0, b = 0, c = 0, d = 0, e = 0;
	int i = 0;

	UNUSED(tc);

	counter = 1;
	result = isc_mutex_init(&set_lock);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

	result = isc_test_begin(NULL, ISC_TRUE);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);

#ifdef ISC_PLATFORM_USETHREADS
	/*
	 * Pause the task manager so we can fill up the work queue
	 * without things happening while we do it.
	 */
	isc__taskmgr_pause(taskmgr);
#endif

	result = isc_task_create(taskmgr, 0, &task1);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	isc_task_setname(task1, "privileged", NULL);
	ATF_CHECK(!isc_task_privilege(task1));
	isc_task_setprivilege(task1, ISC_TRUE);
	ATF_CHECK(isc_task_privilege(task1));

	result = isc_task_create(taskmgr, 0, &task2);
	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
	isc_task_setname(task2, "normal", NULL);
	ATF_CHECK(!isc_task_privilege(task2));

	/* First event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set, &a, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(a, 0);
	isc_task_send(task1, &event);

	/* Second event: not privileged */
	event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
				   set, &b, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(b, 0);
	isc_task_send(task2, &event);

	/* Third event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set, &c, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(c, 0);
	isc_task_send(task1, &event);

	/* Fourth event: privileged */
	event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
				   set, &d, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(d, 0);
	isc_task_send(task1, &event);

	/* Fifth event: not privileged */
	event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
				   set, &e, sizeof (isc_event_t));
	ATF_REQUIRE(event != NULL);

	ATF_CHECK_EQ(e, 0);
	isc_task_send(task2, &event);

	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
	isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);

#ifdef ISC_PLATFORM_USETHREADS
	isc__taskmgr_resume(taskmgr);
#endif

	/* We're waiting for *all* variables to be set */
	while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) {
#ifndef ISC_PLATFORM_USETHREADS
		while (isc__taskmgr_ready(taskmgr))
			isc__taskmgr_dispatch(taskmgr);
#endif
		isc_test_nap(1000);
	}

	/*
	 * We can't guarantee what order the events fire, but
	 * we do know the privileged tasks that set a, c, and d
	 * would have fired first.
	 */
	ATF_CHECK(a <= 3);
	ATF_CHECK(c <= 3);
	ATF_CHECK(d <= 3);

	/* ...and the non-privileged tasks that set b and e, last */
	ATF_CHECK(b >= 4);
	ATF_CHECK(e >= 4);

	ATF_CHECK_EQ(counter, 6);

	isc_task_setprivilege(task1, ISC_FALSE);
	ATF_CHECK(!isc_task_privilege(task1));

	ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);

	isc_task_destroy(&task1);
	ATF_REQUIRE_EQ(task1, NULL);
	isc_task_destroy(&task2);
	ATF_REQUIRE_EQ(task2, NULL);

	isc_test_end();
}