You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
7.9 KiB
C

/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file oslib/src/chdelegates.c
* @brief Delegate threads code.
* @details Delegate threads.
* <h2>Operation mode</h2>
* A delegate thread is a thread performing function calls triggered
* by other threads. This functionality is especially useful when
* encapsulating a library not designed for threading into a
* delegate thread. Other threads have access to the library without
* having to worry about mutual exclusion.
* @pre In order to use the pipes APIs the @p CH_CFG_USE_DELEGATES
* option must be enabled in @p chconf.h.
* @note Compatible with RT and NIL.
*
* @addtogroup oslib_delegates
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_DELEGATES == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing a delegate call.
*/
typedef struct {
/**
* @brief The delegate veneer function.
*/
delegate_veneer_t veneer;
/**
* @brief Pointer to the caller @p va_list object.
*/
va_list *argsp;
} call_message_t;
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/*lint -save -e586 [17.1] Required by design.*/
/**
* @brief Veneer for functions with no parameters.
*
* @param[in] argsp the list of arguments
* @return The function return value.
*/
msg_t __ch_delegate_fn0(va_list *argsp) {
delegate_fn0_t fn0 = (delegate_fn0_t)va_arg(*argsp, delegate_fn0_t);
return fn0();
}
/**
* @brief Veneer for functions with one parameter.
*
* @param[in] argsp the list of arguments
* @return The function return value.
*/
msg_t __ch_delegate_fn1(va_list *argsp) {
delegate_fn1_t fn1 = (delegate_fn1_t)va_arg(*argsp, delegate_fn1_t);
msg_t p1 = (msg_t)va_arg(*argsp, msg_t);
return fn1(p1);
}
/**
* @brief Veneer for functions with two parameters.
*
* @param[in] argsp the list of arguments
* @return The function return value.
*/
msg_t __ch_delegate_fn2(va_list *argsp) {
delegate_fn2_t fn2 = (delegate_fn2_t)va_arg(*argsp, delegate_fn2_t);
msg_t p1 = (msg_t)va_arg(*argsp, msg_t);
msg_t p2 = (msg_t)va_arg(*argsp, msg_t);
return fn2(p1, p2);
}
/**
* @brief Veneer for functions with three parameters.
*
* @param[in] argsp the list of arguments
* @return The function return value.
*/
msg_t __ch_delegate_fn3(va_list *argsp) {
delegate_fn3_t fn3 = (delegate_fn3_t)va_arg(*argsp, delegate_fn3_t);
msg_t p1 = (msg_t)va_arg(*argsp, msg_t);
msg_t p2 = (msg_t)va_arg(*argsp, msg_t);
msg_t p3 = (msg_t)va_arg(*argsp, msg_t);
return fn3(p1, p2, p3);
}
/**
* @brief Veneer for functions with four parameters.
*
* @param[in] argsp the list of arguments
* @return The function return value.
*/
msg_t __ch_delegate_fn4(va_list *argsp) {
delegate_fn4_t fn4 = (delegate_fn4_t)va_arg(*argsp, delegate_fn4_t);
msg_t p1 = (msg_t)va_arg(*argsp, msg_t);
msg_t p2 = (msg_t)va_arg(*argsp, msg_t);
msg_t p3 = (msg_t)va_arg(*argsp, msg_t);
msg_t p4 = (msg_t)va_arg(*argsp, msg_t);
return fn4(p1, p2, p3, p4);
}
/**
* @brief Triggers a function call on a delegate thread.
* @note The thread must be executing @p chDelegateDispatchTimeout() in
* order to have the functions called.
*
* @param[in] tp pointer to the delegate thread
* @param[in] veneer pointer to the veneer function to be called
* @param[in] ... variable number of parameters
* @return The function return value casted to msg_t. It is
* garbage for functions returning @p void.
*/
msg_t chDelegateCallVeneer(thread_t *tp, delegate_veneer_t veneer, ...) {
va_list args;
call_message_t cm;
msg_t msg;
va_start(args, veneer);
/* Preparing the call message.*/
cm.veneer = veneer;
cm.argsp = &args;
(void)cm; /* Suppresses a lint warning.*/
/* Sending the message to the dispatcher thread, the return value is
contained in the returned message.*/
msg = chMsgSend(tp, (msg_t)&cm);
va_end(args);
return msg;
}
/*lint -restore*/
/**
* @brief Call messages dispatching.
* @details The function awaits for an incoming call messages and calls the
* specified functions, then it returns. In case multiple threads
* are sending messages then the requests are served in priority
* order.
*
* @api
*/
void chDelegateDispatch(void) {
thread_t *tp;
const call_message_t *cmp;
msg_t ret;
tp = chMsgWait();
cmp = (const call_message_t *)chMsgGet(tp);
ret = cmp->veneer(cmp->argsp);
chMsgRelease(tp, ret);
}
/**
* @brief Call messages dispatching with timeout.
* @details The function awaits for an incoming call messages and calls the
* specified functions, then it returns. In case multiple threads
* are sending messages then the requests are served in priority
* order.
*
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* @return The function outcome.
* @retval MSG_OK if a function has been called.
* @retval MSG_TIMEOUT if a timeout occurred.
*
* @api
*/
msg_t chDelegateDispatchTimeout(sysinterval_t timeout) {
thread_t *tp;
const call_message_t *cmp;
msg_t ret;
tp = chMsgWaitTimeout(timeout);
if (tp == NULL) {
return MSG_TIMEOUT;
}
cmp = (const call_message_t *)chMsgGet(tp);
ret = cmp->veneer(cmp->argsp);
chMsgRelease(tp, ret);
return MSG_OK;
}
#endif /* CH_CFG_USE_DELEGATES == TRUE */
/** @} */