/* 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 . */ /** * @file oslib/src/chdelegates.c * @brief Delegate threads code. * @details Delegate threads. *

Operation mode

* 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 */ /** @} */