zephyr/kernel/microkernel/k_mailbox.c

986 lines
23 KiB
C

/* mailbox kernel services */
/*
* Copyright (c) 1997-2014 Wind River Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Wind River Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <microkernel.h>
#include <string.h>
#include <toolchain.h>
#include <sections.h>
#include <micro_private.h>
#include <misc/__assert.h>
#include <misc/util.h>
/**
*
* @brief Determines if mailbox message is synchronous or asynchronous
*
* Returns a non-zero value if the specified message contains a valid pool ID,
* indicating that it is an asynchronous message.
*/
#define ISASYNCMSG(message) ((message)->tx_block.poolid != 0)
/**
*
* @brief Copy a packet
*
* @return N/A
*/
static void copy_packet(struct k_args **out, struct k_args *in)
{
GETARGS(*out);
/*
* Copy the data from <in> to <*out> and create
* a backpointer to the original packet.
*/
memcpy(*out, in, sizeof(struct k_args));
(*out)->Ctxt.args = in;
}
/**
*
* @brief Determine if there is a match between the mailbox sender and receiver
*
* @return matched message size, or -1 if no match
*/
static int match(struct k_args *Reader, struct k_args *Writer)
{
if ((Reader->Args.m1.mess.tx_task == ANYTASK ||
Reader->Args.m1.mess.tx_task == Writer->Args.m1.mess.tx_task) &&
(Writer->Args.m1.mess.rx_task == ANYTASK ||
Writer->Args.m1.mess.rx_task == Reader->Args.m1.mess.rx_task)) {
if (!ISASYNCMSG(&(Writer->Args.m1.mess))) {
int32_t info;
Reader->Args.m1.mess.tx_task =
Writer->Args.m1.mess.tx_task;
Writer->Args.m1.mess.rx_task =
Reader->Args.m1.mess.rx_task;
info = Reader->Args.m1.mess.info;
Reader->Args.m1.mess.info = Writer->Args.m1.mess.info;
Writer->Args.m1.mess.info = info;
} else {
Reader->Args.m1.mess.tx_task =
Writer->Args.m1.mess.tx_task;
Reader->Args.m1.mess.tx_data = NULL;
Reader->Args.m1.mess.tx_block =
Writer->Args.m1.mess.tx_block;
Reader->Args.m1.mess.info = Writer->Args.m1.mess.info;
}
if (Reader->Args.m1.mess.size > Writer->Args.m1.mess.size) {
Reader->Args.m1.mess.size = Writer->Args.m1.mess.size;
} else {
Writer->Args.m1.mess.size = Reader->Args.m1.mess.size;
}
/*
* The __ASSERT_NO_MSG() statements are used to verify that
* the -1 will not be returned when there is a match.
*/
__ASSERT_NO_MSG(Writer->Args.m1.mess.size ==
Reader->Args.m1.mess.size);
__ASSERT_NO_MSG((uint32_t)(-1) != Reader->Args.m1.mess.size);
return Reader->Args.m1.mess.size;
}
return -1; /* There was no match */
}
/**
*
* prepare_transfer -
*
* @return true or false
*/
static bool prepare_transfer(struct k_args *move,
struct k_args *reader,
struct k_args *writer)
{
/* extract info from writer and reader before they change: */
/*
* prepare writer and reader cmd packets for 'return':
* (this is shared code, irrespective of the value of 'move')
*/
__ASSERT_NO_MSG(NULL == reader->Forw);
reader->Comm = RECV_ACK;
reader->Time.rcode = RC_OK;
__ASSERT_NO_MSG(NULL == writer->Forw);
writer->alloc = true;
writer->Comm = SEND_ACK;
writer->Time.rcode = RC_OK;
if (move) {
/* { move != NULL, which means full data exchange } */
bool all_data_present = true;
move->Comm = MVD_REQ;
/*
* transfer the data with the highest
* priority of reader and writer
*/
move->Prio = max(writer->Prio, reader->Prio);
move->Ctxt.proc = NULL;
move->Args.MovedReq.Action =
(MovedAction)(MVDACT_SNDACK | MVDACT_RCVACK);
move->Args.MovedReq.iTotalSize = writer->Args.m1.mess.size;
move->Args.MovedReq.Extra.Setup.ContSnd = NULL;
move->Args.MovedReq.Extra.Setup.ContRcv = NULL;
/* reader: */
if (reader->Args.m1.mess.rx_data == NULL) {
all_data_present = false;
__ASSERT_NO_MSG(0 == reader->Args.m1.mess.extra
.transfer); /* == extra.sema */
reader->Args.m1.mess.extra.transfer = move;
/*SENDARGS(reader); */
} else {
move->Args.MovedReq.destination =
reader->Args.m1.mess.rx_data;
writer->Args.m1.mess.rx_data =
reader->Args.m1.mess.rx_data;
/* chain the reader */
move->Args.MovedReq.Extra.Setup.ContRcv = reader;
}
/* writer: */
if (ISASYNCMSG(&(writer->Args.m1.mess))) {
move->Args.MovedReq.source =
writer->Args.m1.mess.tx_block.pointer_to_data;
reader->Args.m1.mess.tx_block =
writer->Args.m1.mess.tx_block;
} else {
__ASSERT_NO_MSG(NULL != writer->Args.m1.mess.tx_data);
move->Args.MovedReq.source =
writer->Args.m1.mess.tx_data;
reader->Args.m1.mess.tx_data =
writer->Args.m1.mess.tx_data;
}
/* chain the writer */
move->Args.MovedReq.Extra.Setup.ContSnd = writer;
return all_data_present;
} else {
/* { NULL == move, which means header exchange only } */
return 0; /* == don't care actually */
}
}
/**
*
* transfer -
*
* @return N/A
*/
static void transfer(struct k_args *pMvdReq)
{
__ASSERT_NO_MSG(NULL != pMvdReq->Args.MovedReq.source);
__ASSERT_NO_MSG(NULL != pMvdReq->Args.MovedReq.destination);
_k_movedata_request(pMvdReq);
FREEARGS(pMvdReq);
}
/**
*
* @brief Process the acknowledgment to a mailbox send request
*
* @return N/A
*/
void _k_mbox_send_ack(struct k_args *pCopyWriter)
{
if (ISASYNCMSG(&(pCopyWriter->Args.m1.mess))) {
if (pCopyWriter->Args.m1.mess.extra.sema) {
/*
* Signal the semaphore. Alternatively, this could
* be done using the continuation mechanism.
*/
struct k_args A;
#ifndef NO_KARG_CLEAR
memset(&A, 0xfd, sizeof(struct k_args));
#endif
A.Comm = SIGNALS;
A.Args.s1.sema = pCopyWriter->Args.m1.mess.extra.sema;
_k_sem_signal(&A);
}
/*
* release the block from the memory pool
* unless this an asynchronous transfer.
*/
if ((uint32_t)(-1) !=
pCopyWriter->Args.m1.mess.tx_block.poolid) {
/*
* special value to tell if block should be
* freed or not
*/
pCopyWriter->Comm = REL_BLOCK;
pCopyWriter->Args.p1.poolid =
pCopyWriter->Args.m1.mess.tx_block.poolid;
pCopyWriter->Args.p1.rep_poolptr =
pCopyWriter->Args.m1.mess.tx_block
.address_in_pool;
pCopyWriter->Args.p1.rep_dataptr =
pCopyWriter->Args.m1.mess.tx_block
.pointer_to_data;
pCopyWriter->Args.p1.req_size =
pCopyWriter->Args.m1.mess.tx_block.req_size;
SENDARGS(pCopyWriter);
return;
} else {
FREEARGS(pCopyWriter);
return;
}
} else {
struct k_args *Starter;
/*
* Get a pointer to the original command packet of the sender
* and copy both the result as well as the message information
* from the received packet of the sender before resetting the
* TF_SEND and TF_SENDDATA state bits.
*/
Starter = pCopyWriter->Ctxt.args;
Starter->Time.rcode = pCopyWriter->Time.rcode;
Starter->Args.m1.mess = pCopyWriter->Args.m1.mess;
_k_state_bit_reset(Starter->Ctxt.proc, TF_SEND | TF_SENDDATA);
FREEARGS(pCopyWriter);
}
}
/**
*
* @brief Process the timeout for a mailbox send request
*
* @return N/A
*/
void _k_mbox_send_reply(struct k_args *pCopyWriter)
{
FREETIMER(pCopyWriter->Time.timer);
REMOVE_ELM(pCopyWriter);
pCopyWriter->Time.rcode = RC_TIME;
pCopyWriter->Comm = SEND_ACK;
SENDARGS(pCopyWriter);
}
/**
*
* @brief Process a mailbox send request
*
* @return N/A
*/
void _k_mbox_send_request(struct k_args *Writer)
{
kmbox_t MailBoxId = Writer->Args.m1.mess.mailbox;
struct mbx_struct *MailBox;
struct k_args *CopyReader;
struct k_args *CopyWriter;
struct k_args *temp;
bool bAsync;
bAsync = ISASYNCMSG(&Writer->Args.m1.mess);
struct k_proc *sender = NULL;
/*
* Only deschedule the task if it is not a poster
* (not an asynchronous request).
*/
if (!bAsync) {
sender = _k_current_task;
_k_state_bit_set(sender, TF_SEND);
}
Writer->Ctxt.proc = sender;
MailBox = _k_mbox_list + OBJ_INDEX(MailBoxId);
copy_packet(&CopyWriter, Writer);
if (bAsync) {
/*
* Clear the [Ctxt] field in an asynchronous request as the
* original packet will not be available later.
*/
CopyWriter->Ctxt.args = NULL;
}
/*
* The [Forw] field can be changed later when added to the Writer's
* list, but when not listed, [Forw] must be NULL.
*/
CopyWriter->Forw = NULL;
for (CopyReader = MailBox->Readers, temp = NULL; CopyReader != NULL;
temp = CopyReader, CopyReader = CopyReader->Forw) {
uint32_t u32Size;
u32Size = match(CopyReader, CopyWriter);
if ((uint32_t)(-1) != u32Size) {
#ifdef CONFIG_OBJECT_MONITOR
MailBox->Count++;
#endif
/*
* There is a match. Remove the chosen reader from the
* list.
*/
if (temp != NULL) {
temp->Forw = CopyReader->Forw;
} else {
MailBox->Readers = CopyReader->Forw;
}
CopyReader->Forw = NULL;
#ifdef CONFIG_SYS_CLOCK_EXISTS
if (CopyReader->Time.timer != NULL) {
/*
* The reader was trying to handshake with
* timeout
*/
_k_timer_delist(CopyReader->Time.timer);
FREETIMER(CopyReader->Time.timer);
}
#endif
if (0 == u32Size) {
/* No data exchange--header only */
prepare_transfer(NULL, CopyReader, CopyWriter);
SENDARGS(CopyReader);
SENDARGS(CopyWriter);
} else {
struct k_args *Moved_req;
GETARGS(Moved_req);
if (prepare_transfer(Moved_req,
CopyReader, CopyWriter)) {
/*
* <Moved_req> will be
* cleared as well
*/
transfer(Moved_req);
} else {
SENDARGS(CopyReader);
}
}
return;
}
}
/* There is no matching receiver for this message. */
if (bAsync) {
/*
* For asynchronous requests, just post the message into the
* list and continue. No further action is required.
*/
INSERT_ELM(MailBox->Writers, CopyWriter);
return;
}
if (CopyWriter->Time.ticks != TICKS_NONE) {
/*
* The writer specified a wait or wait with timeout operation.
*
* Note: Setting the command to SEND_TMO is only necessary in
* the wait with timeout case. However, it is more efficient
* to blindly set it rather than waste time on a comparison.
*/
CopyWriter->Comm = SEND_TMO;
/* Put the letter into the mailbox */
INSERT_ELM(MailBox->Writers, CopyWriter);
#ifdef CONFIG_SYS_CLOCK_EXISTS
if (CopyWriter->Time.ticks == TICKS_UNLIMITED) {
/* This is a wait operation; there is no timer. */
CopyWriter->Time.timer = NULL;
} else {
/*
* This is a wait with timeout operation.
* Enlist a new timeout.
*/
_k_timeout_alloc(CopyWriter);
}
#endif
} else {
/*
* This is a no-wait operation.
* Notify the sender of failure.
*/
CopyWriter->Comm = SEND_ACK;
CopyWriter->Time.rcode = RC_FAIL;
SENDARGS(CopyWriter);
}
}
/**
*
* @brief Send a message to a mailbox
*
* This routine sends a message to a mailbox and looks for a matching receiver.
*
* @return RC_OK, RC_FAIL, RC_TIME on success, failure, timeout respectively
*/
int _task_mbox_put(kmbox_t mbox, /* mailbox */
kpriority_t prio, /* priority of data transfer */
struct k_msg *M, /* pointer to message to send */
int32_t time /* maximum number of ticks to wait */
)
{
struct k_args A;
__ASSERT((0 == M->size) || (NULL != M->tx_data),
"Invalid mailbox data specification\n");
if (unlikely((uint32_t)(-1) == M->size)) {
/* the sender side cannot specify a size of -1 == 0xfff..ff */
return RC_FAIL;
}
M->tx_task = _k_current_task->Ident;
M->tx_block.poolid = 0; /* NO ASYNC POST */
M->extra.sema = 0;
M->mailbox = mbox;
A.Prio = prio;
A.Comm = SEND_REQ;
A.Time.ticks = time;
A.Args.m1.mess = *M;
KERNEL_ENTRY(&A);
*M = A.Args.m1.mess;
return A.Time.rcode;
}
/**
*
* @brief Process a mailbox receive acknowledgment
*
* This routine processes a mailbox receive acknowledgment.
*
* INTERNAL: This routine frees the <pCopyReader> packet
*
* @return N/A
*/
void _k_mbox_receive_ack(struct k_args *pCopyReader)
{
struct k_args *Starter;
/* Get a pointer to the original command packet of the sender */
Starter = pCopyReader->Ctxt.args;
/* Copy result from received packet */
Starter->Time.rcode = pCopyReader->Time.rcode;
/* And copy the message information from the received packet. */
Starter->Args.m1.mess = pCopyReader->Args.m1.mess;
/* Reschedule the sender task */
_k_state_bit_reset(Starter->Ctxt.proc, TF_RECV | TF_RECVDATA);
FREEARGS(pCopyReader);
}
/**
*
* @brief Process the timeout for a mailbox receive request
*
* @return N/A
*/
void _k_mbox_receive_reply(struct k_args *pCopyReader)
{
#ifdef CONFIG_SYS_CLOCK_EXISTS
FREETIMER(pCopyReader->Time.timer);
REMOVE_ELM(pCopyReader);
pCopyReader->Time.rcode = RC_TIME;
pCopyReader->Comm = RECV_ACK;
SENDARGS(pCopyReader);
#endif
}
/**
*
* @brief Process a mailbox receive request
*
* @return N/A
*/
void _k_mbox_receive_request(struct k_args *Reader)
{
kmbox_t MailBoxId = Reader->Args.m1.mess.mailbox;
struct mbx_struct *MailBox;
struct k_args *CopyWriter;
struct k_args *temp;
struct k_args *CopyReader;
Reader->Ctxt.proc = _k_current_task;
_k_state_bit_set(Reader->Ctxt.proc, TF_RECV);
copy_packet(&CopyReader, Reader);
/*
* The [Forw] field can be changed later when added to the Reader's
* list, but when not listed, [Forw] must be NULL.
*/
CopyReader->Forw = NULL;
MailBox = _k_mbox_list + OBJ_INDEX(MailBoxId);
for (CopyWriter = MailBox->Writers, temp = NULL; CopyWriter != NULL;
temp = CopyWriter, CopyWriter = CopyWriter->Forw) {
uint32_t u32Size;
u32Size = match(CopyReader, CopyWriter);
if ((uint32_t)(-1) != u32Size) {
#ifdef CONFIG_OBJECT_MONITOR
MailBox->Count++;
#endif
/*
* There is a match. Remove the chosen reader
* from the list.
*/
if (temp != NULL) {
temp->Forw = CopyWriter->Forw;
} else {
MailBox->Writers = CopyWriter->Forw;
}
CopyWriter->Forw = NULL;
#ifdef CONFIG_SYS_CLOCK_EXISTS
if (CopyWriter->Time.timer != NULL) {
/*
* The writer was trying to handshake with
* timeout.
*/
_k_timer_delist(CopyWriter->Time.timer);
FREETIMER(CopyWriter->Time.timer);
}
#endif
if (0 == u32Size) {
/* No data exchange--header only */
prepare_transfer(NULL, CopyReader, CopyWriter);
SENDARGS(CopyReader);
SENDARGS(CopyWriter);
} else {
struct k_args *Moved_req;
GETARGS(Moved_req);
if (prepare_transfer(Moved_req,
CopyReader, CopyWriter)) {
/*
* <Moved_req> will be
* cleared as well
*/
transfer(Moved_req);
} else {
SENDARGS(CopyReader);
}
}
return;
}
}
/* There is no matching writer for this message. */
if (Reader->Time.ticks != TICKS_NONE) {
/*
* The writer specified a wait or wait with timeout operation.
*
* Note: Setting the command to RECV_TMO is only necessary in
* the wait with timeout case. However, it is more efficient
* to blindly set it rather than waste time on a comparison.
*/
CopyReader->Comm = RECV_TMO;
/* Put the letter into the mailbox */
INSERT_ELM(MailBox->Readers, CopyReader);
#ifdef CONFIG_SYS_CLOCK_EXISTS
if (CopyReader->Time.ticks == TICKS_UNLIMITED) {
/* This is a wait operation; there is no timer. */
CopyReader->Time.timer = NULL;
} else {
/*
* This is a wait with timeout operation.
* Enlist a new timeout.
*/
_k_timeout_alloc(CopyReader);
}
#endif
} else {
/*
* This is a no-wait operation.
* Notify the receiver of failure.
*/
CopyReader->Comm = RECV_ACK;
CopyReader->Time.rcode = RC_FAIL;
SENDARGS(CopyReader);
}
}
/**
*
* @brief Gets struct k_msg message header structure information
* from a mailbox
*
* @return RC_OK, RC_FAIL, RC_TIME on success, failure, timeout respectively
*/
int _task_mbox_get(kmbox_t mbox, /* mailbox */
struct k_msg *M, /* pointer to message */
int32_t time /* maximum number of ticks to wait */
)
{
struct k_args A;
M->rx_task = _k_current_task->Ident;
M->mailbox = mbox;
M->extra.transfer = 0;
/*
* NOTE: to make sure there is no conflict with extra.sema,
* there is an assertion check in prepare_transfer() if equal to 0
*/
A.Prio = _k_current_task->Prio;
A.Comm = RECV_REQ;
A.Time.ticks = time;
A.Args.m1.mess = *M;
KERNEL_ENTRY(&A);
*M = A.Args.m1.mess;
return A.Time.rcode;
}
/**
*
* @brief Send a message asynchronously to a mailbox
*
* This routine sends a message to a mailbox and does not wait for a matching
* receiver. There is no exchange header returned to the sender. When the data
* has been transferred to the receiver, the semaphore signaling is performed.
*
* @return N/A
*/
void _task_mbox_put_async(kmbox_t mbox, /* mailbox to which to send message */
kpriority_t prio, /* priority of data transfer */
struct k_msg *M, /* pointer to message to send */
ksem_t sema /* semaphore to signal when transfer is complete */
)
{
struct k_args A;
__ASSERT(0xFFFFFFFF != M->size, "Invalid mailbox data specification\n");
if (0 == M->size) {
/*
* trick: special value to indicate that tx_block
* should NOT be released in the SND_ACK
*/
M->tx_block.poolid = (uint32_t)(-1);
}
M->tx_task = _k_current_task->Ident;
M->tx_data = NULL;
M->mailbox = mbox;
M->extra.sema = sema;
#ifdef CONFIG_SYS_CLOCK_EXISTS
A.Time.timer = NULL;
#endif
A.Prio = prio;
A.Comm = SEND_REQ;
A.Args.m1.mess = *M;
KERNEL_ENTRY(&A);
}
/**
*
* @brief Process a mailbox receive data request
*
* @return N/A
*/
void _k_mbox_receive_data(struct k_args *Starter)
{
struct k_args *CopyStarter;
struct k_args *MoveD;
struct k_args *Writer;
Starter->Ctxt.proc = _k_current_task;
_k_state_bit_set(_k_current_task, TF_RECVDATA);
GETARGS(CopyStarter);
memcpy(CopyStarter, Starter, sizeof(struct k_args));
CopyStarter->Ctxt.args = Starter;
MoveD = CopyStarter->Args.m1.mess.extra.transfer;
CopyStarter->Comm = RECV_ACK;
CopyStarter->Time.rcode = RC_OK;
MoveD->Args.MovedReq.Extra.Setup.ContRcv = CopyStarter;
CopyStarter->Forw = NULL;
MoveD->Args.MovedReq.destination = CopyStarter->Args.m1.mess.rx_data;
MoveD->Args.MovedReq.iTotalSize = CopyStarter->Args.m1.mess.size;
Writer = MoveD->Args.MovedReq.Extra.Setup.ContSnd;
if (Writer != NULL) {
if (ISASYNCMSG(&(Writer->Args.m1.mess))) {
CopyStarter->Args.m1.mess.tx_block =
Writer->Args.m1.mess.tx_block;
} else {
Writer->Args.m1.mess.rx_data =
CopyStarter->Args.m1.mess.rx_data;
CopyStarter->Args.m1.mess.tx_data =
Writer->Args.m1.mess.tx_data;
}
transfer(MoveD); /* and MoveD will be cleared as well */
}
}
/**
*
* @brief Get message data
*
* This routine is called for either of the two following purposes:
* 1. To transfer data if the call to task_mbox_get() resulted in a non-zero size
* field in the struct k_msg header structure.
* 2. To wake up and release a transmitting task that is blocked on a call to
* task_mbox_put[wait|wait_timeout]().
*
* @return N/A
*/
void _task_mbox_data_get(struct k_msg *M /* message from which to get data */
)
{
struct k_args A;
/* sanity checks */
if (unlikely(NULL == M->extra.transfer)) {
/*
* protection: if a user erroneously calls this function after
* a task_mbox_get(), we should not run into trouble
*/
return;
}
A.Args.m1.mess = *M;
A.Comm = RECV_DATA;
KERNEL_ENTRY(&A);
}
/**
*
* @brief Get the mailbox data and place
* in a memory pool block
*
* @return RC_OK upon success, RC_FAIL upon failure, or RC_TIME upon timeout
*/
int _task_mbox_data_get_async_block(struct k_msg *message,
struct k_block *rxblock,
kmemory_pool_t poolid,
int32_t time)
{
int retval;
struct k_args *MoveD;
/* sanity checks: */
if (NULL == message->extra.transfer) {
/*
* If a user erroneously calls this function after a
* task_mbox_get(), we should not run into trouble.
* Return RC_OK instead of RC_FAIL to be downwards compatible.
*/
return RC_OK;
}
/* special flow to check for possible optimisations: */
if (ISASYNCMSG(message)) {
/* First transfer block */
__ASSERT_NO_MSG(-1 != message->tx_block.poolid);
*rxblock = message->tx_block;
/* This is the MOVED packet */
MoveD = message->extra.transfer;
/* Then release sender (writer) */
struct k_args *Writer;
/*
* This is the first of the continuation packets for
* continuation on send. It should be the only one.
* That is, it should not have any followers. To
* prevent [tx_block] from being released when the
* SEND_ACK is processed, change its [poolid] to -1.
*/
Writer = MoveD->Args.MovedReq.Extra.Setup.ContSnd;
__ASSERT_NO_MSG(NULL != Writer);
__ASSERT_NO_MSG(NULL == Writer->Forw);
Writer->Args.m1.mess.tx_block.poolid = (uint32_t)(-1);
nano_task_stack_push(&_k_command_stack, (uint32_t)Writer);
#ifdef ACTIV_ASSERTS
struct k_args *Dummy;
/*
* Confirm that there are not any continuation packets
* for continuation on receive.
*/
Dummy = MoveD->Args.MovedReq.Extra.Setup.ContRcv;
__ASSERT_NO_MSG(NULL == Dummy);
#endif
FREEARGS(MoveD); /* Clean up MOVED */
return RC_OK;
}
/* 'normal' flow of task_mbox_data_get_async_block(): */
if (0 != message->size) {
retval = _task_mem_pool_alloc(rxblock, poolid,
message->size, time);
if (retval != RC_OK) {
return retval;
}
message->rx_data = rxblock->pointer_to_data;
} else {
rxblock->poolid = (kmemory_pool_t) -1;
}
/*
* Invoke task_mbox_data_get() core without sanity checks, as they have
* already been performed.
*/
struct k_args A;
A.Args.m1.mess = *message;
A.Comm = RECV_DATA;
KERNEL_ENTRY(&A);
return RC_OK; /* task_mbox_data_get() doesn't return anything */
}
/**
*
* @brief Process a mailbox send data request
*
* @return N/A
*/
void _k_mbox_send_data(struct k_args *Starter)
{
struct k_args *CopyStarter;
struct k_args *MoveD;
struct k_args *Reader;
Starter->Ctxt.proc = _k_current_task;
_k_state_bit_set(_k_current_task, TF_SENDDATA);
GETARGS(CopyStarter);
memcpy(CopyStarter, Starter, sizeof(struct k_args));
CopyStarter->Ctxt.args = Starter;
MoveD = CopyStarter->Args.m1.mess.extra.transfer;
CopyStarter->Time.rcode = RC_OK;
CopyStarter->Comm = SEND_ACK;
MoveD->Args.MovedReq.Extra.Setup.ContSnd = CopyStarter;
CopyStarter->Forw = NULL;
MoveD->Args.MovedReq.source = CopyStarter->Args.m1.mess.rx_data;
Reader = MoveD->Args.MovedReq.Extra.Setup.ContRcv;
if (Reader != NULL) {
Reader->Args.m1.mess.rx_data =
CopyStarter->Args.m1.mess.rx_data;
CopyStarter->Args.m1.mess.tx_data =
Reader->Args.m1.mess.tx_data;
transfer(MoveD); /* and MoveD will be cleared as well */
}
}