Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 1997-2010, 2013-2014 Wind River Systems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file
 * @brief FIFO kernel services
 *
 * This file contains all the services needed for the implementation of a FIFO
 * for the microkernel.
 *
 *
*/


#include <micro_private.h>
#include <string.h>
#include <toolchain.h>
#include <sections.h>

/**
 *
 * @brief Finish performing an incomplete FIFO enqueue request
 *
 * @return N/A
 */
void _k_fifo_enque_reply(struct k_args *A)
{
#ifdef CONFIG_SYS_CLOCK_EXISTS
	if (A->Time.timer)
		FREETIMER(A->Time.timer);
	if (unlikely(A->Comm == _K_SVC_FIFO_ENQUE_REPLY_TIMEOUT)) {
		REMOVE_ELM(A);
		A->Time.rcode = RC_TIME;
	} else {
		A->Time.rcode = RC_OK;
	}
#else
	A->Time.rcode = RC_OK;
#endif

	_k_state_bit_reset(A->Ctxt.task, TF_ENQU);
}

/**
 *
 * @brief Finish performing an incomplete FIFO enqueue request with timeout.
 *
 * @param A Pointer to a k_args structure
 *
 * @return N/A
 *
 * @sa _k_fifo_enque_reply
 */
void _k_fifo_enque_reply_timeout(struct k_args *A)
{
	_k_fifo_enque_reply(A);
}

/**
 *
 * @brief Perform a FIFO enqueue request
 *
 * @return N/A
 */
void _k_fifo_enque_request(struct k_args *A)
{
	struct k_args *W;
	struct _k_fifo_struct *Q;
	int Qid, n, w;
	char *p, *q; /* Ski char->uint32_t ??? */

	Qid = A->args.q1.queue;
	Q = (struct _k_fifo_struct *)Qid;
	w = OCTET_TO_SIZEOFUNIT(Q->element_size);
	q = A->args.q1.data;
	n = Q->num_used;
	if (n < Q->Nelms) {
		W = Q->waiters;
		if (W) {
			Q->waiters = W->next;
			p = W->args.q1.data;
			memcpy(p, q, w);

#ifdef CONFIG_SYS_CLOCK_EXISTS
			if (W->Time.timer) {
				_k_timeout_cancel(W);
				W->Comm = _K_SVC_FIFO_DEQUE_REPLY;
			} else {
#endif
				W->Time.rcode = RC_OK;
					_k_state_bit_reset(W->Ctxt.task, TF_DEQU);
			}
#ifdef CONFIG_SYS_CLOCK_EXISTS
		}
#endif
		else {
			p = Q->enqueue_point;
			memcpy(p, q, w);
			p = (char *)((int)p + w);
			if (p == Q->end_point)
				Q->enqueue_point = Q->base;
			else
				Q->enqueue_point = p;
			Q->num_used = ++n;
#ifdef CONFIG_OBJECT_MONITOR
			if (Q->high_watermark < n)
				Q->high_watermark = n;
#endif
		}

		A->Time.rcode = RC_OK;
#ifdef CONFIG_OBJECT_MONITOR
		Q->count++;
#endif
	} else {
		if (likely(A->Time.ticks != TICKS_NONE)) {
			A->Ctxt.task = _k_current_task;
			A->priority = _k_current_task->priority;
			_k_state_bit_set(_k_current_task, TF_ENQU);
			INSERT_ELM(Q->waiters, A);
#ifdef CONFIG_SYS_CLOCK_EXISTS
			if (A->Time.ticks == TICKS_UNLIMITED)
				A->Time.timer = NULL;
			else {
				A->Comm = _K_SVC_FIFO_ENQUE_REPLY_TIMEOUT;
				_k_timeout_alloc(A);
			}
#endif
		} else {
			A->Time.rcode = RC_FAIL;
		}
	}
}

int task_fifo_put(kfifo_t queue, void *data, int32_t timeout)
{
	struct k_args A;

	A.Comm = _K_SVC_FIFO_ENQUE_REQUEST;
	A.Time.ticks = timeout;
	A.args.q1.data = (char *)data;
	A.args.q1.queue = queue;

	KERNEL_ENTRY(&A);

	return A.Time.rcode;
}

/**
 *
 * @brief Finish performing an incomplete FIFO dequeue request
 *
 * @return N/A
 */
void _k_fifo_deque_reply(struct k_args *A)
{
#ifdef CONFIG_SYS_CLOCK_EXISTS
	if (A->Time.timer)
		FREETIMER(A->Time.timer);
	if (unlikely(A->Comm == _K_SVC_FIFO_DEQUE_REPLY_TIMEOUT)) {
		REMOVE_ELM(A);
		A->Time.rcode = RC_TIME;
	} else {
		A->Time.rcode = RC_OK;
	}
#else
	A->Time.rcode = RC_OK;
#endif

	_k_state_bit_reset(A->Ctxt.task, TF_DEQU);
}

/**
 *
 * @brief Finish performing an incomplete FIFO dequeue request with timeout.
 *
 * @param A Pointer to a k_args structure.
 *
 * @return N/A
 *
 * @sa _k_fifo_deque_reply
 */
void _k_fifo_deque_reply_timeout(struct k_args *A)
{
	_k_fifo_deque_reply(A);
}

/**
 *
 * @brief Perform FIFO dequeue request
 *
 * @return N/A
 */
void _k_fifo_deque_request(struct k_args *A)
{
	struct k_args *W;
	struct _k_fifo_struct *Q;
	int Qid, n, w;
	char *p, *q; /* idem */

	Qid = A->args.q1.queue;
	Q = (struct _k_fifo_struct *)Qid;
	w = OCTET_TO_SIZEOFUNIT(Q->element_size);
	p = A->args.q1.data;
	n = Q->num_used;
	if (n) {
		q = Q->dequeue_point;
		memcpy(p, q, w);
		q = (char *)((int)q + w);
		if (q == Q->end_point)
			Q->dequeue_point = Q->base;
		else
			Q->dequeue_point = q;

		A->Time.rcode = RC_OK;
		W = Q->waiters;
		if (W) {
			Q->waiters = W->next;
			p = Q->enqueue_point;
			q = W->args.q1.data;
			w = OCTET_TO_SIZEOFUNIT(Q->element_size);
			memcpy(p, q, w);
			p = (char *)((int)p + w);
			if (p == Q->end_point)
				Q->enqueue_point = Q->base;
			else
				Q->enqueue_point = p;

#ifdef CONFIG_SYS_CLOCK_EXISTS
			if (W->Time.timer) {
				_k_timeout_cancel(W);
				W->Comm = _K_SVC_FIFO_ENQUE_REPLY;
			} else {
#endif
				W->Time.rcode = RC_OK;
				_k_state_bit_reset(W->Ctxt.task, TF_ENQU);
#ifdef CONFIG_SYS_CLOCK_EXISTS
			}
#endif
#ifdef CONFIG_OBJECT_MONITOR
			Q->count++;
#endif
		} else
			Q->num_used = --n;
	} else {
		if (likely(A->Time.ticks != TICKS_NONE)) {
			A->Ctxt.task = _k_current_task;
			A->priority = _k_current_task->priority;
			_k_state_bit_set(_k_current_task, TF_DEQU);

			INSERT_ELM(Q->waiters, A);
#ifdef CONFIG_SYS_CLOCK_EXISTS
			if (A->Time.ticks == TICKS_UNLIMITED)
				A->Time.timer = NULL;
			else {
				A->Comm = _K_SVC_FIFO_DEQUE_REPLY_TIMEOUT;
				_k_timeout_alloc(A);
			}
#endif
		} else {
			A->Time.rcode = RC_FAIL;
		}
	}
}

int task_fifo_get(kfifo_t queue, void *data, int32_t timeout)
{
	struct k_args A;

	A.Comm = _K_SVC_FIFO_DEQUE_REQUEST;
	A.Time.ticks = timeout;
	A.args.q1.data = (char *)data;
	A.args.q1.queue = queue;

	KERNEL_ENTRY(&A);

	return A.Time.rcode;
}

/**
 *
 * @brief Perform miscellaneous FIFO request
 * @param A Kernel Argument
 *
 * @return N/A
 */
void _k_fifo_ioctl(struct k_args *A)
{
	struct _k_fifo_struct *Q;
	int Qid;

	Qid = A->args.q1.queue;
	Q = (struct _k_fifo_struct *)Qid;
	if (A->args.q1.size) {
		if (Q->num_used) {
			struct k_args *X;

			while ((X = Q->waiters)) {
				Q->waiters = X->next;
#ifdef CONFIG_SYS_CLOCK_EXISTS
				if (likely(X->Time.timer)) {
					_k_timeout_cancel(X);
					X->Comm = _K_SVC_FIFO_ENQUE_REPLY;
				} else {
#endif
					X->Time.rcode = RC_FAIL;
					_k_state_bit_reset(X->Ctxt.task, TF_ENQU);
#ifdef CONFIG_SYS_CLOCK_EXISTS
				}
#endif
			}
		}
		Q->num_used = 0;
		Q->enqueue_point = Q->dequeue_point = Q->base;
		A->Time.rcode = RC_OK;
	} else
		A->Time.rcode = Q->num_used;
}

/**
 *
 * @brief Miscellaneous FIFO request
 *
 * Depending upon the chosen operation, this routine will ...
 *   1. <op> = 0 : query the number of FIFO entries
 *   2. <op> = 1 : purge the FIFO of its entries
 *
 * @param queue FIFO queue
 * @param op 0 for status query and 1 for purge
 * @return # of FIFO entries on query; RC_OK on purge
 */
int _task_fifo_ioctl(kfifo_t queue, int op)
{
	struct k_args A;

	A.Comm = _K_SVC_FIFO_IOCTL;
	A.args.q1.queue = queue;
	A.args.q1.size = op;
	KERNEL_ENTRY(&A);
	return A.Time.rcode;
}