zephyr/kernel/microkernel/k_pipe_put.c

308 lines
8.3 KiB
C

/* command processing for pipe put operation */
/*
* Copyright (c) 1997-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.
*/
#include <micro_private.h>
#include <k_pipe_util.h>
#include <toolchain.h>
#include <sections.h>
#include <misc/__assert.h>
/**
*
* @brief Process request command for a pipe put operation
*
* @return N/A
*/
void _k_pipe_put_request(struct k_args *RequestOrig)
{
struct k_args *Request;
struct k_args *RequestProc;
kpipe_t pipeId = RequestOrig->args.pipe_req.req_info.pipe.id;
bool bAsync;
if (_k_pipe_request_type_get(&RequestOrig->args) == _ASYNCREQ) {
bAsync = true;
} else {
bAsync = false;
}
if (!bAsync) {
/* First save the pointer to the task's TCB for rescheduling later */
RequestOrig->Ctxt.task = _k_current_task;
_k_state_bit_set(_k_current_task, TF_SEND);
} else {
/* No need to put in data about sender, since it's a poster */
RequestOrig->Ctxt.task = NULL;
}
mycopypacket(&Request, RequestOrig);
/* Now, we need a new packet for processing of the request; the
* Request package is too small b/c of space lost due to possible
* embedded local data
*/
mycopypacket(&RequestProc, Request);
RequestProc->args.pipe_xfer_req.req_info.pipe.ptr =
(struct _k_pipe_struct *)pipeId;
switch (_k_pipe_request_type_get(&RequestProc->args)) {
case _SYNCREQ:
RequestProc->args.pipe_xfer_req.data_ptr =
Request->args.pipe_req.req_type.sync.data_ptr;
RequestProc->args.pipe_xfer_req.total_size =
Request->args.pipe_req.req_type.sync.total_size;
break;
case _ASYNCREQ:
RequestProc->args.pipe_xfer_req.data_ptr =
Request->args.pipe_req.req_type.async.block.pointer_to_data;
RequestProc->args.pipe_xfer_req.total_size =
Request->args.pipe_req.req_type.async.total_size;
break;
default:
break;
}
RequestProc->args.pipe_xfer_req.status = XFER_IDLE;
RequestProc->args.pipe_xfer_req.num_pending_xfers = 0;
RequestProc->args.pipe_xfer_req.xferred_size = 0;
RequestProc->next = NULL;
RequestProc->head = NULL;
switch (RequestProc->Time.ticks) {
case TICKS_NONE:
_k_pipe_time_type_set(&RequestProc->args, _TIME_NB);
break;
case TICKS_UNLIMITED:
_k_pipe_time_type_set(&RequestProc->args, _TIME_B);
break;
default:
_k_pipe_time_type_set(&RequestProc->args, _TIME_BT);
break;
}
/* start processing */
struct _k_pipe_struct *pipe_ptr;
pipe_ptr = RequestProc->args.pipe_xfer_req.req_info.pipe.ptr;
do {
int iSpace2WriteinReaders;
int iFreeBufferSpace;
int iTotalSpace2Write;
int32_t ticks;
iSpace2WriteinReaders = CalcFreeReaderSpace(pipe_ptr->readers);
iFreeBufferSpace =
pipe_ptr->desc.free_space_count +
pipe_ptr->desc.free_space_post_wrap_around;
iTotalSpace2Write =
iFreeBufferSpace + iSpace2WriteinReaders;
if (iTotalSpace2Write == 0)
break; /* special case b/c even not good enough for 1_TO_N */
/* (possibly) do some processing */
ticks = RequestProc->Time.ticks;
RequestProc->Time.timer = NULL;
_k_pipe_process(pipe_ptr, RequestProc /* writer */, NULL /* reader */);
RequestProc->Time.ticks = ticks;
/* check if request was processed */
if (TERM_XXX & RequestProc->args.pipe_xfer_req.status) {
/* not really required */
RequestProc->Time.timer = NULL;
/* not listed anymore --> completely processed */
return;
}
} while (0);
/*
* if we got up to here, we did none or SOME (partial)
* processing on the request
*/
if (_k_pipe_time_type_get(&RequestProc->args) != _TIME_NB) {
/* call is blocking */
INSERT_ELM(pipe_ptr->writers, RequestProc);
/*
* NOTE: It is both faster and simpler to blindly assign the
* PIPE_PUT_TIMEOUT microkernel command to the packet even
* though it is only useful to the finite timeout case.
*/
RequestProc->Comm = _K_SVC_PIPE_PUT_TIMEOUT;
if (_k_pipe_time_type_get(&RequestProc->args) == _TIME_B) {
/*
* The writer specified TICKS_UNLIMITED; NULL the timer.
*/
RequestProc->Time.timer = NULL;
return;
}
/* { TIME_BT } */
#ifdef CANCEL_TIMERS
if (RequestProc->args.pipe_xfer_req.xferred_size != 0) {
RequestProc->Time.timer = NULL;
} else
#endif
/* enlist a new timer into the timeout chain */
_k_timeout_alloc(RequestProc);
return;
}
/*
* call is non-blocking;
* Check if we don't have to queue it b/c it could not
* be processed at once
*/
RequestProc->Time.timer = NULL;
if (RequestProc->args.pipe_xfer_req.status == XFER_BUSY) {
INSERT_ELM(pipe_ptr->writers, RequestProc);
} else {
__ASSERT_NO_MSG(RequestProc->args.pipe_xfer_req.status == XFER_IDLE);
__ASSERT_NO_MSG(RequestProc->args.pipe_xfer_req.xferred_size == 0);
RequestProc->Comm = _K_SVC_PIPE_PUT_REPLY;
_k_pipe_put_reply(RequestProc);
}
return;
}
/**
*
* @brief Perform timeout command for a pipe put operation
*
* @return N/A
*/
void _k_pipe_put_timeout(struct k_args *ReqProc)
{
__ASSERT_NO_MSG(ReqProc->Time.timer != NULL);
myfreetimer(&(ReqProc->Time.timer));
_k_pipe_request_status_set(&ReqProc->args.pipe_xfer_req, TERM_TMO);
DeListWaiter(ReqProc);
if (ReqProc->args.pipe_xfer_req.num_pending_xfers == 0) {
_k_pipe_put_reply(ReqProc);
}
}
/**
*
* @brief Process reply command for a pipe put operation
*
* @return N/A
*/
void _k_pipe_put_reply(struct k_args *ReqProc)
{
__ASSERT_NO_MSG(
ReqProc->args.pipe_xfer_req.num_pending_xfers == 0 /* no pending Xfers */
&& ReqProc->Time.timer == NULL /* no pending timer */
&& ReqProc->head == NULL); /* not in list */
/* orig packet must be sent back, not ReqProc */
struct k_args *ReqOrig = ReqProc->Ctxt.args;
PIPE_REQUEST_STATUS status;
ReqOrig->Comm = _K_SVC_PIPE_PUT_ACK;
/* determine return value:
*/
status = ReqProc->args.pipe_xfer_req.status;
if (unlikely(status == TERM_TMO)) {
ReqOrig->Time.rcode = RC_TIME;
} else if ((TERM_XXX | XFER_IDLE) & status) {
K_PIPE_OPTION Option = _k_pipe_option_get(&ReqProc->args);
if (likely(ReqProc->args.pipe_xfer_req.xferred_size ==
ReqProc->args.pipe_xfer_req.total_size)) {
/* All data has been transferred */
ReqOrig->Time.rcode = RC_OK;
} else if (ReqProc->args.pipe_xfer_req.xferred_size != 0) {
/* Some but not all data has been transferred */
ReqOrig->Time.rcode = (Option == _ALL_N) ? RC_INCOMPLETE : RC_OK;
} else {
/* No data has been transferred */
ReqOrig->Time.rcode = (Option == _0_TO_N) ? RC_OK : RC_FAIL;
}
} else {
/* unknown (invalid) status */
__ASSERT_NO_MSG(1 == 0); /* should not come here */
}
if (_k_pipe_request_type_get(&ReqOrig->args) != _ASYNCREQ) {
ReqOrig->args.pipe_ack.xferred_size =
ReqProc->args.pipe_xfer_req.xferred_size;
}
SENDARGS(ReqOrig);
FREEARGS(ReqProc);
}
/**
*
* @brief Process acknowledgment command for a pipe put operation
*
* @return N/A
*/
void _k_pipe_put_ack(struct k_args *Request)
{
if (_k_pipe_request_type_get(&Request->args) == _ASYNCREQ) {
struct _pipe_ack_arg *pipe_ack = &Request->args.pipe_ack;
struct k_args A;
struct k_block *blockptr;
/* invoke command to release block */
blockptr = &pipe_ack->req_type.async.block;
A.Comm = _K_SVC_MEM_POOL_BLOCK_RELEASE;
A.args.p1.pool_id = blockptr->pool_id;
A.args.p1.req_size = blockptr->req_size;
A.args.p1.rep_poolptr = blockptr->address_in_pool;
A.args.p1.rep_dataptr = blockptr->pointer_to_data;
_k_mem_pool_block_release(&A); /* will return immediately */
if (pipe_ack->req_type.async.sema != (ksem_t)NULL) {
/* invoke command to signal sema */
struct k_args A;
A.Comm = _K_SVC_SEM_SIGNAL;
A.args.s1.sema = pipe_ack->req_type.async.sema;
_k_sem_signal(&A); /* will return immediately */
}
} else {
/* Reschedule the sender task */
struct k_args *LocalReq;
LocalReq = Request->Ctxt.args;
LocalReq->Time.rcode = Request->Time.rcode;
LocalReq->args.pipe_ack = Request->args.pipe_ack;
_k_state_bit_reset(LocalReq->Ctxt.task, TF_SEND | TF_SENDDATA);
}
FREEARGS(Request);
}