Example #1
0
static int
mm_port_receive_internal(struct mm_port *port, uint32_t *start, uint32_t count, bool blocking)
{
	ENTER();
	ASSERT(count <= (MM_PORT_SIZE / 2));
	ASSERT(port->task == mm_task_selfptr());
	int rc = 0;

again:
	mm_regular_lock(&port->lock);
	if (port->count < count) {
		mm_regular_unlock(&port->lock);
		if (blocking) {
			mm_task_block();
			mm_task_testcancel();
			goto again;
		} else {
			rc = -1;
			goto leave;
		}
	}

	uint32_t *ring_ptr = &port->ring[port->start];

	port->count -= count;

	if (unlikely((port->start + count) > MM_PORT_SIZE)) {
		uint32_t top_count = MM_PORT_SIZE - port->start;
		count -= top_count;
		while (top_count--) {
			*start++ = *ring_ptr++;
		}

		ring_ptr = &port->ring[0];
		port->start = 0;
	}

	port->start = (port->start + count) % MM_PORT_SIZE;
	while (count--) {
		*start++ = *ring_ptr++;
	}

	mm_waitset_broadcast(&port->blocked_senders, &port->lock);

leave:
	LEAVE();
	return rc;
}
Example #2
0
mm_task_combiner_execute(struct mm_task_combiner *combiner,
			 mm_combiner_routine_t routine, uintptr_t data)
{
	ENTER();

	// Disable cancellation as the enqueue algorithm cannot be
	// safely undone if interrupted in the middle.
	int cancelstate;
	mm_task_setcancelstate(MM_TASK_CANCEL_DISABLE, &cancelstate);

	// Get per-core queue of pending requests.
	mm_core_t core = mm_core_self();
	struct mm_list *wait_queue = MM_THREAD_LOCAL_DEREF(core, combiner->wait_queue);

	// Add the current request to the per-core queue.
	struct mm_task *task = mm_task_selfptr();
	task->flags |= MM_TASK_COMBINING;
	mm_list_append(wait_queue, &task->wait_queue);

	// Wait until the current request becomes the head of the
	// per-core queue.
	while (mm_list_head(wait_queue) != &task->wait_queue)
		mm_task_block();

	mm_combiner_execute(&combiner->combiner, routine, data);

	// Remove the request from the per-core queue.
	mm_list_delete(&task->wait_queue);
	task->flags &= ~MM_TASK_COMBINING;

	// If the per-core queue is not empty then let its new head take
	// the next turn.
	if (!mm_list_empty(wait_queue)) {
		struct mm_link *link = mm_list_head(wait_queue);
		task = containerof(link, struct mm_task, wait_queue);
		mm_task_run(task);
	}

	// Restore cancellation.
	mm_task_setcancelstate(cancelstate, NULL);

	LEAVE();
}