263 lines
7.0 KiB
C
263 lines
7.0 KiB
C
/* command processing for pipe get 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 get operation
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _k_pipe_get_request(struct k_args *RequestOrig)
|
|
{
|
|
struct k_args *Request;
|
|
struct k_args *RequestProc;
|
|
|
|
kpipe_t pipeId = RequestOrig->args.pipe_req.req_info.pipe.id;
|
|
|
|
/* If it's a poster, then don't deschedule the task */
|
|
|
|
/* First we 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_RECV);
|
|
|
|
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;
|
|
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 iData2ReadFromWriters;
|
|
int iAvailBufferData;
|
|
int iTotalData2Read;
|
|
int32_t ticks;
|
|
|
|
iData2ReadFromWriters = CalcAvailWriterData(pipe_ptr->writers);
|
|
iAvailBufferData =
|
|
pipe_ptr->desc.available_data_count +
|
|
pipe_ptr->desc.available_data_post_wrap_around;
|
|
iTotalData2Read =
|
|
iAvailBufferData + iData2ReadFromWriters;
|
|
|
|
if (iTotalData2Read == 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, NULL /* writer */, RequestProc /* reader */);
|
|
RequestProc->Time.ticks = ticks;
|
|
|
|
/* check if request was processed */
|
|
if (TERM_XXX & RequestProc->args.pipe_xfer_req.status) {
|
|
RequestProc->Time.timer = NULL; /* not really required */
|
|
return; /* not listed anymore --> completely processed */
|
|
}
|
|
|
|
} while (0);
|
|
|
|
/*
|
|
* if we got up to here, we did none or SOME (partial)
|
|
* processing on the request
|
|
*/
|
|
|
|
if (_TIME_NB != _k_pipe_time_type_get(&RequestProc->args)) {
|
|
/* call is blocking */
|
|
INSERT_ELM(pipe_ptr->readers, RequestProc);
|
|
/*
|
|
* NOTE: It is both faster and simpler to blindly assign the
|
|
* PIPE_GET_TIMEOUT microkernel command to the packet even though it
|
|
* is only useful to the finite timeout case.
|
|
*/
|
|
RequestProc->Comm = _K_SVC_PIPE_GET_TIMEOUT;
|
|
if (_k_pipe_time_type_get(&RequestProc->args) == _TIME_B) {
|
|
/*
|
|
* The writer specified TICKS_UNLIMITED, so 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->readers, 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_GET_REPLY;
|
|
_k_pipe_get_reply(RequestProc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Process timeout command for a pipe get operation
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _k_pipe_get_timeout(struct k_args *ReqProc)
|
|
{
|
|
__ASSERT_NO_MSG(NULL != ReqProc->Time.timer);
|
|
|
|
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_get_reply(ReqProc);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Process reply command for a pipe get operation
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _k_pipe_get_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_GET_ACK;
|
|
|
|
/* determine return value */
|
|
|
|
status = ReqProc->args.pipe_xfer_req.status;
|
|
if (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 */
|
|
}
|
|
|
|
ReqOrig->args.pipe_ack.xferred_size =
|
|
ReqProc->args.pipe_xfer_req.xferred_size;
|
|
SENDARGS(ReqOrig);
|
|
|
|
FREEARGS(ReqProc);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Process acknowledgment command for a pipe get operation
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _k_pipe_get_ack(struct k_args *Request)
|
|
{
|
|
struct k_args *LocalReq;
|
|
|
|
LocalReq = Request->Ctxt.args;
|
|
LocalReq->Time.rcode = Request->Time.rcode;
|
|
LocalReq->args.pipe_ack = Request->args.pipe_ack;
|
|
|
|
/* Reschedule the sender task */
|
|
|
|
_k_state_bit_reset(LocalReq->Ctxt.task, TF_RECV | TF_RECVDATA);
|
|
|
|
FREEARGS(Request);
|
|
}
|