Пример #1
0
static void
iris_thread_worker_exclusive (IrisThread  *thread,
                              IrisQueue   *queue,
                              gboolean     leader)
{
	GTimeVal        tv_now      = {0,0};
	GTimeVal        tv_req      = {0,0};
	IrisThreadWork *thread_work = NULL;
	gint            per_quanta = 0;      /* Completed items within the
	                                      * last quanta. */
	guint           queued      = 0;     /* Items left in the queue at */
	gboolean        has_resized = FALSE;

	iris_debug (IRIS_DEBUG_THREAD);

	g_get_current_time (&tv_now);
	g_get_current_time (&tv_req);
	queued = iris_queue_length (queue);

	/* Since our thread is in exclusive mode, we are responsible for
	 * asking the scheduler manager to add or remove threads based
	 * on the demand of our work queue.
	 *
	 * If the scheduler has maxed out the number of threads it is
	 * allowed, then we will not ask the scheduler to add more
	 * threads and rebalance.
	 */

get_next_item:

	if (G_LIKELY ((thread_work = iris_queue_pop (queue)) != NULL)) {
		if (!VERIFY_THREAD_WORK (thread_work))
			goto get_next_item;

		iris_thread_work_run (thread_work);
		iris_thread_work_free (thread_work);
		per_quanta++;
	}
	else {
#if 0
		g_warning ("Exclusive thread is done managing, received NULL");
#endif
		return;
	}

	if (G_UNLIKELY (!thread->scheduler->maxed && leader)) {
		g_get_current_time (&tv_now);

		if (G_UNLIKELY (timeout_elapsed (&tv_now, &tv_req))) {
			/* We check to see if we have a bunch more work to do
			 * or a potential edge case where we are processing about
			 * the same speed as the pusher, but it creates enough
			 * contention where we dont speed up. This is because
			 * some schedulers will round-robin or steal.  And unless
			 * we look to add another thread even though we have nothing
			 * in the queue, we know there are more coming.
			 */
			queued = iris_queue_length (queue);
			if (queued == 0 && !has_resized) {
				queued = per_quanta * 2;
				has_resized = TRUE;
			}

			if (per_quanta < queued) {
				/* make sure we are not maxed before asking */
				if (!g_atomic_int_get (&thread->scheduler->maxed))
					iris_scheduler_manager_request (thread->scheduler,
									per_quanta,
									queued);
			}

			per_quanta = 0;
			tv_req = tv_now;
			g_time_val_add (&tv_req, QUANTUM_USECS);
		}
	}

	goto get_next_item;
}
Пример #2
0
static void
iris_thread_worker_exclusive (IrisThread  *thread,
                              IrisQueue   *queue,
                              gboolean     leader)
{
	GTimeVal        tv_now      = {0,0};
	GTimeVal        tv_req      = {0,0};
	IrisThreadWork *thread_work = NULL;
	gint            per_quanta = 0;      /* Completed items within the
	                                      * last quanta. */
	guint           queued      = 0;     /* Items left in the queue at */
	gboolean        has_resized = FALSE;
	gboolean        remove_work;

	iris_debug (IRIS_DEBUG_THREAD);

	g_get_current_time (&tv_now);
	g_get_current_time (&tv_req);
	queued = iris_queue_get_length (queue);

	/* Since our thread is in exclusive mode, we are responsible for
	 * asking the scheduler manager to add or remove threads based
	 * on the demand of our work queue.
	 *
	 * If the scheduler has maxed out the number of threads it is
	 * allowed, then we will not ask the scheduler to add more
	 * threads and rebalance.
	 */

get_next_item:

	if (G_LIKELY ((thread_work = iris_queue_pop (queue)) != NULL)) {
		if (!g_atomic_int_compare_and_exchange(&thread_work->taken, FALSE, TRUE)) {
			remove_work = g_atomic_int_get (&thread_work->remove);

			if (!remove_work)
				/* We lost a race with another thread (remember a lockfree
				 * queue may pop the same item twice). 
				 */
				goto get_next_item;
			/* else: We lost a race with iris_scheduler_unqueue() */
		} else
			/* We won the race. 'remove' is honoured anyway if we can. */
			remove_work = g_atomic_int_get (&thread_work->remove);

		if (!remove_work) {
			iris_thread_work_run (thread_work);
			per_quanta++;
		}

		iris_thread_work_free (thread_work);
	}
	else {
		/* Queue is closed, so scheduler is finalizing. The scheduler will be
		 * waiting until we set thread->scheduler to NULL.
		 */
		g_atomic_pointer_set (&thread->scheduler, NULL);
		iris_scheduler_manager_yield (thread);
		return;
	}

	if (remove_work)
		goto get_next_item;

	if (G_UNLIKELY (!thread->scheduler->maxed && leader)) {
		g_get_current_time (&tv_now);

		if (G_UNLIKELY (timeout_elapsed (&tv_now, &tv_req))) {
			/* We check to see if we have a bunch more work to do
			 * or a potential edge case where we are processing about
			 * the same speed as the pusher, but it creates enough
			 * contention where we dont speed up. This is because
			 * some schedulers will round-robin or steal.  And unless
			 * we look to add another thread even though we have nothing
			 * in the queue, we know there are more coming.
			 */
			queued = iris_queue_get_length (queue);
			if (queued == 0 && !has_resized) {
				queued = per_quanta * 2;
				has_resized = TRUE;
			}

			if (per_quanta < queued) {
				/* make sure we are not maxed before asking */
				if (!g_atomic_int_get (&thread->scheduler->maxed))
					iris_scheduler_manager_request (thread->scheduler,
									per_quanta,
									queued);
			}

			per_quanta = 0;
			tv_req = tv_now;
			g_time_val_add (&tv_req, QUANTUM_USECS);
		}
	}

	goto get_next_item;
}