541 lines
14 KiB
C
541 lines
14 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) 2014-2016, Freescale Semiconductor, Inc.
|
||
|
|
* Copyright 2016-2023 NXP
|
||
|
|
* Copyright 2021 ACRIOS Systems s.r.o.
|
||
|
|
* All rights reserved.
|
||
|
|
*
|
||
|
|
*
|
||
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef __embedded_rpc__thread__
|
||
|
|
#define __embedded_rpc__thread__
|
||
|
|
|
||
|
|
#include "erpc_config_internal.h"
|
||
|
|
|
||
|
|
#include <stdint.h>
|
||
|
|
|
||
|
|
// Exclude the rest of the file if threading is disabled.
|
||
|
|
#if !ERPC_THREADS_IS(NONE)
|
||
|
|
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
#include <pthread.h>
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
#include "FreeRTOS.h"
|
||
|
|
#include "semphr.h"
|
||
|
|
#include "task.h"
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
#include <zephyr/kernel.h>
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
#if MBED_CONF_RTOS_PRESENT
|
||
|
|
#include "rtos.h"
|
||
|
|
#else
|
||
|
|
#warning mbed-rpc: Threading is enabled but Mbed RTOS is not present!
|
||
|
|
#endif
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
#include "windows.h"
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
#include "tx_api.h"
|
||
|
|
|
||
|
|
#endif // ERPC_THREADS
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @addtogroup port_threads
|
||
|
|
* @{
|
||
|
|
* @file
|
||
|
|
*/
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// Types
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
//! @brief Thread function type.
|
||
|
|
//!
|
||
|
|
//! @param arg User provided argument that was passed into the start() method.
|
||
|
|
typedef void (*thread_entry_t)(void *arg);
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// Declarations
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
#if defined(__cplusplus)
|
||
|
|
|
||
|
|
namespace erpc {
|
||
|
|
/*!
|
||
|
|
* @brief Simple thread class.
|
||
|
|
*
|
||
|
|
* @ingroup port_threads
|
||
|
|
*/
|
||
|
|
class Thread
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
//! @brief Unique identifier for a thread.
|
||
|
|
typedef void *thread_id_t;
|
||
|
|
#if ERPC_THREADS_IS(FREERTOS)
|
||
|
|
typedef StackType_t *thread_stack_pointer;
|
||
|
|
#else
|
||
|
|
typedef void *thread_stack_pointer;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Default constructor for use with the init() method.
|
||
|
|
*
|
||
|
|
* If this constructor is used, the init() method must be called before the thread can be
|
||
|
|
* started.
|
||
|
|
*
|
||
|
|
* @param[in] name Optional name for the thread.
|
||
|
|
*/
|
||
|
|
Thread(const char *name = 0);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Constructor.
|
||
|
|
*
|
||
|
|
* This constructor fully initializes the thread object.
|
||
|
|
*
|
||
|
|
* @param[in] entry
|
||
|
|
* @param[in] priority
|
||
|
|
* @param[in] stackSize
|
||
|
|
* @param[in] name Optional name for the thread.
|
||
|
|
* @param[in] stackPtr Mandatory task stack pointer for static api usage.
|
||
|
|
*/
|
||
|
|
Thread(thread_entry_t entry, uint32_t priority = 0, uint32_t stackSize = 0, const char *name = 0,
|
||
|
|
thread_stack_pointer stackPtr = NULL);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Destructor.
|
||
|
|
*/
|
||
|
|
virtual ~Thread(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function sets name for thread.
|
||
|
|
*
|
||
|
|
* @param[in] name Name for thread.
|
||
|
|
*/
|
||
|
|
void setName(const char *name) { m_name = name; }
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function returns name of thread.
|
||
|
|
*
|
||
|
|
* @return Name of thread.
|
||
|
|
*/
|
||
|
|
const char *getName(void) const { return m_name; }
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function initializes thread.
|
||
|
|
*
|
||
|
|
* @param[in] entry Entry function.
|
||
|
|
* @param[in] priority Task priority.
|
||
|
|
* @param[in] stackSize Stack size.
|
||
|
|
* @param[in] stackPtr Mandatory task stack pointer for static api usage.
|
||
|
|
*/
|
||
|
|
void init(thread_entry_t entry, uint32_t priority = 0, uint32_t stackSize = 0,
|
||
|
|
thread_stack_pointer stackPtr = NULL);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function starts thread execution.
|
||
|
|
*
|
||
|
|
* @param[in] arg Function argument.
|
||
|
|
*/
|
||
|
|
void start(void *arg = 0);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function puts thread to sleep.
|
||
|
|
*
|
||
|
|
* @param[in] usecs Time for sleeping in [us].
|
||
|
|
*/
|
||
|
|
static void sleep(uint32_t usecs);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function returns current thread id.
|
||
|
|
*
|
||
|
|
* @return Thread id.
|
||
|
|
*/
|
||
|
|
thread_id_t getThreadId(void) const
|
||
|
|
{
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_thread);
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_task);
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_thread_id);
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_thread->get_id());
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_thread);
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
return reinterpret_cast<thread_id_t>(m_thread.tx_thread_id);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function returns thread id where function is called.
|
||
|
|
*
|
||
|
|
* @return Thread id.
|
||
|
|
*/
|
||
|
|
static thread_id_t getCurrentThreadId(void)
|
||
|
|
{
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
return reinterpret_cast<thread_id_t>(pthread_self());
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
return reinterpret_cast<thread_id_t>(xTaskGetCurrentTaskHandle());
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
return reinterpret_cast<thread_id_t>(k_current_get());
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
return reinterpret_cast<thread_id_t>(rtos::ThisThread::get_id());
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
return reinterpret_cast<thread_id_t>(GetCurrentThread());
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
return reinterpret_cast<thread_id_t>(tx_thread_identify());
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
#if ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
/*!
|
||
|
|
* @brief This function sets stack pointer for Zephyr task.
|
||
|
|
*
|
||
|
|
* @param[in] stack Stack pointer.
|
||
|
|
*/
|
||
|
|
void setStackPointer(k_thread_stack_t *stack) { m_stack = stack; }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function returns Thread instance where functions is called.
|
||
|
|
*
|
||
|
|
* @return Thread instance.
|
||
|
|
*/
|
||
|
|
static Thread *getCurrentThread(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Compare operator compares two threads.
|
||
|
|
*
|
||
|
|
* @param[in] o Thread instance.
|
||
|
|
*
|
||
|
|
* @retval true When threads are same.
|
||
|
|
* @retval false When threads aren't same.
|
||
|
|
*/
|
||
|
|
bool operator==(Thread &o);
|
||
|
|
|
||
|
|
protected:
|
||
|
|
/*!
|
||
|
|
* @brief This function execute entry function.
|
||
|
|
*/
|
||
|
|
virtual void threadEntryPoint(void);
|
||
|
|
|
||
|
|
private:
|
||
|
|
const char *m_name; /*!< Thread name. */
|
||
|
|
thread_entry_t m_entry; /*!< Thread entry function. */
|
||
|
|
void *m_arg; /*!< Entry parameter. */
|
||
|
|
uint32_t m_stackSize; /*!< Stack size. */
|
||
|
|
uint32_t m_priority; /*!< Task priority. */
|
||
|
|
thread_stack_pointer m_stackPtr; /*!< Task pointer. */
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
static pthread_key_t s_threadObjectKey; /*!< Thread key. */
|
||
|
|
pthread_t m_thread; /*!< Current thread. */
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
TaskHandle_t m_task; /*!< Current task. */
|
||
|
|
Thread *m_next; /*!< Pointer to next Thread. */
|
||
|
|
static Thread *s_first; /*!< Pointer to first Thread. */
|
||
|
|
#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_STATIC
|
||
|
|
StaticTask_t m_staticTask; /*!< Hold static task data. */
|
||
|
|
#endif
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
struct k_thread m_thread; /*!< Current thread. */
|
||
|
|
k_tid_t m_thread_id;
|
||
|
|
k_thread_stack_t *m_stack; /*!< Pointer to stack. */
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
rtos::Thread *m_thread; /*!< Underlying Thread instance */
|
||
|
|
Thread *m_next; /*!< Pointer to next Thread. */
|
||
|
|
static Thread *s_first; /*!< Pointer to first Thread. */
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
HANDLE m_thread;
|
||
|
|
unsigned int m_thrdaddr;
|
||
|
|
Thread *m_next; /*!< Pointer to next Thread. */
|
||
|
|
static Thread *s_first; /*!< Pointer to first Thread. */
|
||
|
|
static CRITICAL_SECTION m_critical_section;
|
||
|
|
static BOOL m_critical_section_inited;
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
TX_THREAD m_thread; /*!< Underlying Thread instance */
|
||
|
|
Thread *m_next; /*!< Pointer to next Thread. */
|
||
|
|
static Thread *s_first; /*!< Pointer to first Thread. */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg Thread to execute.
|
||
|
|
*/
|
||
|
|
static void *threadEntryPointStub(void *arg);
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg Thread to execute.
|
||
|
|
*/
|
||
|
|
static void threadEntryPointStub(void *arg);
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg1 Thread to execute.
|
||
|
|
* @param[in] arg2
|
||
|
|
* @param[in] arg3
|
||
|
|
*/
|
||
|
|
static void threadEntryPointStub(void *arg1, void *arg2, void *arg3);
|
||
|
|
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg Thread to execute.
|
||
|
|
*/
|
||
|
|
static void threadEntryPointStub(void *arg);
|
||
|
|
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg Thread to execute.
|
||
|
|
*/
|
||
|
|
static unsigned WINAPI threadEntryPointStub(void *arg);
|
||
|
|
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function execute threadEntryPoint function.
|
||
|
|
*
|
||
|
|
* @param[in] arg Thread to execute.
|
||
|
|
*/
|
||
|
|
static void threadEntryPointStub(ULONG arg);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
private:
|
||
|
|
/*!
|
||
|
|
* @brief Copy constructor.
|
||
|
|
*
|
||
|
|
* @param[in] o Thread to copy.
|
||
|
|
*/
|
||
|
|
Thread(const Thread &o);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Assign operator.
|
||
|
|
*
|
||
|
|
* @param[in] o Thread to assign.
|
||
|
|
*/
|
||
|
|
Thread &operator=(const Thread &o);
|
||
|
|
};
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Mutex.
|
||
|
|
*
|
||
|
|
* If the OS supports it, the mutex will be recursive.
|
||
|
|
*
|
||
|
|
* @ingroup port_threads
|
||
|
|
*/
|
||
|
|
class Mutex
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
/*!
|
||
|
|
* @brief
|
||
|
|
*/
|
||
|
|
class Guard
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
/*!
|
||
|
|
* @brief Constructor.
|
||
|
|
*
|
||
|
|
* @param[in] mutex to lock.
|
||
|
|
*/
|
||
|
|
Guard(Mutex &mutex) : m_mutex(mutex) { (void)m_mutex.lock(); }
|
||
|
|
/*!
|
||
|
|
* @brief Destructor.
|
||
|
|
*/
|
||
|
|
~Guard(void) { (void)m_mutex.unlock(); }
|
||
|
|
|
||
|
|
private:
|
||
|
|
Mutex &m_mutex; /*!< Mutex to lock. */
|
||
|
|
};
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Constructor.
|
||
|
|
*/
|
||
|
|
Mutex(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Destructor.
|
||
|
|
*/
|
||
|
|
~Mutex(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function try lock mutex.
|
||
|
|
*
|
||
|
|
* @retval true When mutex locked successfully.
|
||
|
|
* @retval false When mutex didn't locked.
|
||
|
|
*/
|
||
|
|
bool tryLock(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function lock mutex.
|
||
|
|
*
|
||
|
|
* @retval true When mutex locked successfully.
|
||
|
|
* @retval false When mutex didn't locked.
|
||
|
|
*/
|
||
|
|
bool lock(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function unlock mutex.
|
||
|
|
*
|
||
|
|
* @retval true When mutex unlocked successfully.
|
||
|
|
* @retval false When mutex didn't unlocked.
|
||
|
|
*/
|
||
|
|
bool unlock(void);
|
||
|
|
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
/*!
|
||
|
|
* @brief This function returns pointer to mutex.
|
||
|
|
*
|
||
|
|
* @return Pointer to mutex.
|
||
|
|
*/
|
||
|
|
pthread_mutex_t *getPtr(void) { return &m_mutex; }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
private:
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
pthread_mutex_t m_mutex; /*!< Mutex.*/
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
SemaphoreHandle_t m_mutex; /*!< Mutex.*/
|
||
|
|
StaticSemaphore_t m_staticQueue; /*!< Static queue. */
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
struct k_mutex m_mutex; /*!< Mutex.*/
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
rtos::Mutex *m_mutex; /*!< Mutex. */
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
HANDLE m_mutex;
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
TX_MUTEX m_mutex;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
private:
|
||
|
|
/*!
|
||
|
|
* @brief Copy constructor.
|
||
|
|
*
|
||
|
|
* @param[in] o Mutex to copy.
|
||
|
|
*/
|
||
|
|
Mutex(const Mutex &o);
|
||
|
|
/*!
|
||
|
|
* @brief Copy constructor.
|
||
|
|
*
|
||
|
|
* @param[in] o Mutex to copy.
|
||
|
|
*/
|
||
|
|
Mutex &operator=(const Mutex &o);
|
||
|
|
};
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Simple semaphore class.
|
||
|
|
*
|
||
|
|
* @ingroup port_threads
|
||
|
|
*/
|
||
|
|
class Semaphore
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
/*!
|
||
|
|
* @brief Variable for semaphore to wait forever.
|
||
|
|
*/
|
||
|
|
static const uint32_t kWaitForever = 0xffffffffu;
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Constructor.
|
||
|
|
*
|
||
|
|
* @param[in] count Semaphore number.
|
||
|
|
*/
|
||
|
|
Semaphore(int count = 0);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief Destructor.
|
||
|
|
*/
|
||
|
|
~Semaphore(void);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function puts semaphore.
|
||
|
|
*/
|
||
|
|
void put(void);
|
||
|
|
|
||
|
|
#if ERPC_THREADS_IS(FREERTOS)
|
||
|
|
/*!
|
||
|
|
* @brief This function puts semaphore from interrupt.
|
||
|
|
*/
|
||
|
|
void putFromISR(void);
|
||
|
|
#endif // ERPC_HAS_FREERTOS
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function get semaphore.
|
||
|
|
*
|
||
|
|
* @param[in] timeoutUsecs Time how long can wait for getting semaphore in [us].
|
||
|
|
*
|
||
|
|
* @retval true When semaphore got successfully.
|
||
|
|
* @retval false When failed getting semaphore or if timeout expired.
|
||
|
|
*/
|
||
|
|
bool get(uint32_t timeoutUsecs = kWaitForever);
|
||
|
|
|
||
|
|
/*!
|
||
|
|
* @brief This function returns semaphore count number.
|
||
|
|
*
|
||
|
|
* @return Semaphore count number.
|
||
|
|
*/
|
||
|
|
int getCount(void) const;
|
||
|
|
|
||
|
|
private:
|
||
|
|
#if ERPC_THREADS_IS(PTHREADS)
|
||
|
|
int m_count; /*!< Semaphore count number. */
|
||
|
|
pthread_cond_t m_cond; /*!< Condition variable. Allows threads to suspend execution and relinquish the processors
|
||
|
|
until some predicate on shared data is satisfied. */
|
||
|
|
Mutex m_mutex; /*!< Mutext. */
|
||
|
|
#elif ERPC_THREADS_IS(FREERTOS)
|
||
|
|
SemaphoreHandle_t m_sem; /*!< Semaphore. */
|
||
|
|
StaticSemaphore_t m_staticQueue; /*!< Static queue. */
|
||
|
|
#elif ERPC_THREADS_IS(ZEPHYR)
|
||
|
|
struct k_sem m_sem; /*!< Semaphore. */
|
||
|
|
#elif ERPC_THREADS_IS(MBED)
|
||
|
|
rtos::Semaphore *m_sem; /*!< Semaphore. */
|
||
|
|
int m_count; /*!< Semaphore count number. */
|
||
|
|
#elif ERPC_THREADS_IS(WIN32)
|
||
|
|
Mutex m_mutex; /*!< Mutext. */
|
||
|
|
int m_count;
|
||
|
|
HANDLE m_sem;
|
||
|
|
#elif ERPC_THREADS_IS(THREADX)
|
||
|
|
TX_SEMAPHORE m_sem; /*!< Semaphore. */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
private:
|
||
|
|
/*!
|
||
|
|
* @brief Copy constructor.
|
||
|
|
*
|
||
|
|
* @param[in] o Semaphore to copy.
|
||
|
|
*/
|
||
|
|
Semaphore(const Semaphore &o);
|
||
|
|
/*!
|
||
|
|
* @brief Copy constructor.
|
||
|
|
*
|
||
|
|
* @param[in] o Semaphore to copy.
|
||
|
|
*/
|
||
|
|
Semaphore &operator=(const Semaphore &o);
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace erpc
|
||
|
|
|
||
|
|
#endif // defined(__cplusplus)
|
||
|
|
|
||
|
|
/*! @} */
|
||
|
|
|
||
|
|
#endif // ERPC_THREADS
|
||
|
|
|
||
|
|
#endif // defined(__embedded_rpc__thread__)
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// EOF
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|