/* 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 chschd.c * @brief Scheduler code. * * @addtogroup scheduler * @details This module provides the default portable scheduler code. * @{ */ #include "ch.h" /*===========================================================================*/ /* Module local definitions. */ /*===========================================================================*/ /*===========================================================================*/ /* Module exported variables. */ /*===========================================================================*/ /** * @brief System data structures. */ ch_system_t ch; /*===========================================================================*/ /* Module local types. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local functions. */ /*===========================================================================*/ /*===========================================================================*/ /* Module exported functions. */ /*===========================================================================*/ /** * @brief Scheduler initialization. * * @notapi */ void _scheduler_init(void) { queue_init(&ch.rlist.queue); ch.rlist.prio = NOPRIO; #if CH_CFG_USE_REGISTRY == TRUE ch.rlist.newer = (thread_t *)&ch.rlist; ch.rlist.older = (thread_t *)&ch.rlist; #endif } #if (CH_CFG_OPTIMIZE_SPEED == FALSE) || defined(__DOXYGEN__) /** * @brief Inserts a thread into a priority ordered queue. * @note The insertion is done by scanning the list from the highest * priority toward the lowest. * * @param[in] tp the pointer to the thread to be inserted in the list * @param[in] tqp the pointer to the threads list header * * @notapi */ void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) { thread_t *cp = (thread_t *)tqp; do { cp = cp->queue.next; } while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio)); tp->queue.next = cp; tp->queue.prev = cp->queue.prev; tp->queue.prev->queue.next = tp; cp->queue.prev = tp; } /** * @brief Inserts a thread into a queue. * * @param[in] tp the pointer to the thread to be inserted in the list * @param[in] tqp the pointer to the threads list header * * @notapi */ void queue_insert(thread_t *tp, threads_queue_t *tqp) { tp->queue.next = (thread_t *)tqp; tp->queue.prev = tqp->prev; tp->queue.prev->queue.next = tp; tqp->prev = tp; } /** * @brief Removes the first-out thread from a queue and returns it. * @note If the queue is priority ordered then this function returns the * thread with the highest priority. * * @param[in] tqp the pointer to the threads list header * @return The removed thread pointer. * * @notapi */ thread_t *queue_fifo_remove(threads_queue_t *tqp) { thread_t *tp = tqp->next; tqp->next = tp->queue.next; tqp->next->queue.prev = (thread_t *)tqp; return tp; } /** * @brief Removes the last-out thread from a queue and returns it. * @note If the queue is priority ordered then this function returns the * thread with the lowest priority. * * @param[in] tqp the pointer to the threads list header * @return The removed thread pointer. * * @notapi */ thread_t *queue_lifo_remove(threads_queue_t *tqp) { thread_t *tp = tqp->prev; tqp->prev = tp->queue.prev; tqp->prev->queue.next = (thread_t *)tqp; return tp; } /** * @brief Removes a thread from a queue and returns it. * @details The thread is removed from the queue regardless of its relative * position and regardless the used insertion method. * * @param[in] tp the pointer to the thread to be removed from the queue * @return The removed thread pointer. * * @notapi */ thread_t *queue_dequeue(thread_t *tp) { tp->queue.prev->queue.next = tp->queue.next; tp->queue.next->queue.prev = tp->queue.prev; return tp; } /** * @brief Pushes a thread_t on top of a stack list. * * @param[in] tp the pointer to the thread to be inserted in the list * @param[in] tlp the pointer to the threads list header * * @notapi */ void list_insert(thread_t *tp, threads_list_t *tlp) { tp->queue.next = tlp->next; tlp->next = tp; } /** * @brief Pops a thread from the top of a stack list and returns it. * @pre The list must be non-empty before calling this function. * * @param[in] tlp the pointer to the threads list header * @return The removed thread pointer. * * @notapi */ thread_t *list_remove(threads_list_t *tlp) { thread_t *tp = tlp->next; tlp->next = tp->queue.next; return tp; } #endif /* CH_CFG_OPTIMIZE_SPEED */ /** * @brief Inserts a thread in the Ready List placing it behind its peers. * @details The thread is positioned behind all threads with higher or equal * priority. * @pre The thread must not be already inserted in any list through its * @p next and @p prev or list corruption would occur. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] tp the thread to be made ready * @return The thread pointer. * * @iclass */ thread_t *chSchReadyI(thread_t *tp) { thread_t *cp; chDbgCheckClassI(); chDbgCheck(tp != NULL); chDbgAssert((tp->state != CH_STATE_READY) && (tp->state != CH_STATE_FINAL), "invalid state"); tp->state = CH_STATE_READY; cp = (thread_t *)&ch.rlist.queue; do { cp = cp->queue.next; } while (cp->prio >= tp->prio); /* Insertion on prev.*/ tp->queue.next = cp; tp->queue.prev = cp->queue.prev; tp->queue.prev->queue.next = tp; cp->queue.prev = tp; return tp; } /** * @brief Inserts a thread in the Ready List placing it ahead its peers. * @details The thread is positioned ahead all threads with higher or equal * priority. * @pre The thread must not be already inserted in any list through its * @p next and @p prev or list corruption would occur. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] tp the thread to be made ready * @return The thread pointer. * * @iclass */ thread_t *chSchReadyAheadI(thread_t *tp) { thread_t *cp; chDbgCheckClassI(); chDbgCheck(tp != NULL); chDbgAssert((tp->state != CH_STATE_READY) && (tp->state != CH_STATE_FINAL), "invalid state"); tp->state = CH_STATE_READY; cp = (thread_t *)&ch.rlist.queue; do { cp = cp->queue.next; } while (cp->prio > tp->prio); /* Insertion on prev.*/ tp->queue.next = cp; tp->queue.prev = cp->queue.prev; tp->queue.prev->queue.next = tp; cp->queue.prev = tp; return tp; } /** * @brief Puts the current thread to sleep into the specified state. * @details The thread goes into a sleeping state. The possible * @ref thread_states are defined into @p threads.h. * * @param[in] newstate the new thread state * * @sclass */ void chSchGoSleepS(tstate_t newstate) { thread_t *otp = currp; chDbgCheckClassS(); /* New state.*/ otp->state = newstate; #if CH_CFG_TIME_QUANTUM > 0 /* The thread is renouncing its remaining time slices so it will have a new time quantum when it will wakeup.*/ otp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM; #endif /* Next thread in ready list becomes current.*/ currp = queue_fifo_remove(&ch.rlist.queue); currp->state = CH_STATE_CURRENT; /* Handling idle-enter hook.*/ if (currp->prio == IDLEPRIO) { CH_CFG_IDLE_ENTER_HOOK(); } /* Swap operation as tail call.*/ chSysSwitch(currp, otp); } /* * Timeout wakeup callback. */ static void wakeup(void *p) { thread_t *tp = (thread_t *)p; chSysLockFromISR(); switch (tp->state) { case CH_STATE_READY: /* Handling the special case where the thread has been made ready by another thread with higher priority.*/ chSysUnlockFromISR(); return; case CH_STATE_SUSPENDED: *tp->u.wttrp = NULL; break; #if CH_CFG_USE_SEMAPHORES == TRUE case CH_STATE_WTSEM: chSemFastSignalI(tp->u.wtsemp); #endif /* Falls through.*/ case CH_STATE_QUEUED: /* Falls through.*/ #if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) case CH_STATE_WTCOND: #endif /* States requiring dequeuing.*/ (void) queue_dequeue(tp); break; default: /* Any other state, nothing to do.*/ break; } tp->u.rdymsg = MSG_TIMEOUT; (void) chSchReadyI(tp); chSysUnlockFromISR(); } /** * @brief Puts the current thread to sleep into the specified state with * timeout specification. * @details The thread goes into a sleeping state, if it is not awakened * explicitly within the specified timeout then it is forcibly * awakened with a @p MSG_TIMEOUT low level message. The possible * @ref thread_states are defined into @p threads.h. * * @param[in] newstate the new thread state * @param[in] timeout the number of ticks before the operation timeouts, the * special values are handled as follow: * - @a TIME_INFINITE the thread enters an infinite sleep * state, this is equivalent to invoking * @p chSchGoSleepS() but, of course, less efficient. * - @a TIME_IMMEDIATE this value is not allowed. * . * @return The wakeup message. * @retval MSG_TIMEOUT if a timeout occurs. * * @sclass */ msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) { chDbgCheckClassS(); if (TIME_INFINITE != timeout) { virtual_timer_t vt; chVTDoSetI(&vt, timeout, wakeup, currp); chSchGoSleepS(newstate); if (chVTIsArmedI(&vt)) { chVTDoResetI(&vt); } } else { chSchGoSleepS(newstate); } return currp->u.rdymsg; } /** * @brief Wakes up a thread. * @details The thread is inserted into the ready list or immediately made * running depending on its relative priority compared to the current * thread. * @pre The thread must not be already inserted in any list through its * @p next and @p prev or list corruption would occur. * @note It is equivalent to a @p chSchReadyI() followed by a * @p chSchRescheduleS() but much more efficient. * @note The function assumes that the current thread has the highest * priority. * * @param[in] ntp the thread to be made ready * @param[in] msg the wakeup message * * @sclass */ void chSchWakeupS(thread_t *ntp, msg_t msg) { thread_t *otp = currp; chDbgCheckClassS(); chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) || (ch.rlist.current->prio >= ch.rlist.queue.next->prio), "priority order violation"); /* Storing the message to be retrieved by the target thread when it will restart execution.*/ ntp->u.rdymsg = msg; /* If the waken thread has a not-greater priority than the current one then it is just inserted in the ready list else it made running immediately and the invoking thread goes in the ready list instead.*/ if (ntp->prio <= otp->prio) { (void) chSchReadyI(ntp); } else { otp = chSchReadyI(otp); /* Handling idle-leave hook.*/ if (otp->prio == IDLEPRIO) { CH_CFG_IDLE_LEAVE_HOOK(); } /* The extracted thread is marked as current.*/ currp = ntp; ntp->state = CH_STATE_CURRENT; /* Swap operation as tail call.*/ chSysSwitch(ntp, otp); } } /** * @brief Performs a reschedule if a higher priority thread is runnable. * @details If a thread with a higher priority than the current thread is in * the ready list then make the higher priority thread running. * * @sclass */ void chSchRescheduleS(void) { chDbgCheckClassS(); if (chSchIsRescRequiredI()) { chSchDoRescheduleAhead(); } } #if !defined(CH_SCH_IS_PREEMPTION_REQUIRED_HOOKED) /** * @brief Evaluates if preemption is required. * @details The decision is taken by comparing the relative priorities and * depending on the state of the round robin timeout counter. * @note Not a user function, it is meant to be invoked by the scheduler * itself or from within the port layer. * * @retval true if there is a thread that must go in running state * immediately. * @retval false if preemption is not required. * * @special */ bool chSchIsPreemptionRequired(void) { tprio_t p1 = firstprio(&ch.rlist.queue); tprio_t p2 = currp->prio; #if CH_CFG_TIME_QUANTUM > 0 /* If the running thread has not reached its time quantum, reschedule only if the first thread on the ready queue has a higher priority. Otherwise, if the running thread has used up its time quantum, reschedule if the first thread on the ready queue has equal or higher priority.*/ return (currp->ticks > (tslices_t)0) ? (p1 > p2) : (p1 >= p2); #else /* If the round robin preemption feature is not enabled then performs a simpler comparison.*/ return p1 > p2; #endif } #endif /* !defined(CH_SCH_IS_PREEMPTION_REQUIRED_HOOKED) */ /** * @brief Switches to the first thread on the runnable queue. * @details The current thread is positioned in the ready list behind all * threads having the same priority. The thread regains its time * quantum. * @note Not a user function, it is meant to be invoked by the scheduler * itself. * * @special */ void chSchDoRescheduleBehind(void) { thread_t *otp = currp; /* Picks the first thread from the ready queue and makes it current.*/ currp = queue_fifo_remove(&ch.rlist.queue); currp->state = CH_STATE_CURRENT; /* Handling idle-leave hook.*/ if (otp->prio == IDLEPRIO) { CH_CFG_IDLE_LEA
/*
    ChibiOS - Copyright (C) 2006..2016 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    chfactory.h
 * @brief   ChibiOS objects factory structures and macros.
 *
 * @addtogroup objects_factory
 * @{
 */

#ifndef CHFACTORY_H
#define CHFACTORY_H

#if !defined(CH_CFG_USE_FACTORY)
#define CH_CFG_USE_FACTORY                  FALSE
#endif

#if (CH_CFG_USE_FACTORY == TRUE) || defined(__DOXYGEN__)

/*===========================================================================*/
/* Module constants.                                                         */
/*===========================================================================*/

/*===========================================================================*/
/* Module pre-compile time settings.                                         */
/*===========================================================================*/

/**
 * @brief   Maximum length for object names.
 * @details If the specified length is zero then the name is stored by
 *          pointer but this could have unintended side effects.
 */
#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_MAX_NAMES_LENGTH     8
#endif

/**
 * @brief   Enables the registry of generic objects.
 */
#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_OBJECTS_REGISTRY     TRUE
#endif

/**
 * @brief   Enables factory for generic buffers.
 */
#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_GENERIC_BUFFERS      TRUE
#endif

/**
 * @brief   Enables factory for semaphores.
 */
#if !defined(CH_CFG_FACTORY_SEMAPHORES) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_SEMAPHORES           TRUE
#endif

/**
 * @brief   Enables factory for mailboxes.
 */
#if !defined(CH_CFG_FACTORY_MAILBOXES) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_MAILBOXES            TRUE
#endif

/**
 * @brief   Enables factory for objects FIFOs.
 */
#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) || defined(__DOXYGEN__)
#define CH_CFG_FACTORY_OBJ_FIFOS            TRUE
#endif

/*===========================================================================*/
/* Derived constants and error checks.                                       */
/*===========================================================================*/

#define CH_FACTORY_REQUIRES_POOLS                                           \
  ((CH_CFG_FACTORY_SEMAPHORES == TRUE))

#define CH_FACTORY_REQUIRES_HEAP                                            \
  ((CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) ||                              \
   (CH_CFG_FACTORY_MAILBOXES == TRUE) ||                                    \
   (CH_CFG_FACTORY_OBJ_FIFOS == TRUE))

#if (CH_CFG_FACTORY_MAX_NAMES_LENGTH < 0) ||                                \
    (CH_CFG_FACTORY_MAX_NAMES_LENGTH > 32)
#error "invalid CH_CFG_FACTORY_MAX_NAMES_LENGTH value"
#endif

#if CH_CFG_USE_MEMCORE == FALSE
#error "CH_CFG_USE_FACTORY requires CH_CFG_USE_MEMCORE"
#endif

#if (CH_FACTORY_REQUIRES_POOLS == TRUE) && (CH_CFG_USE_MEMPOOLS == FALSE)
#error "CH_CFG_USE_MEMPOOLS is required"
#endif

#if (CH_FACTORY_REQUIRES_HEAP == TRUE) && (CH_CFG_USE_HEAP == FALSE)
#error "CH_CFG_USE_HEAP is required"
#endif

#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) && (CH_CFG_USE_SEMAPHORES == FALSE)
#error "CH_CFG_FACTORY_SEMAPHORES requires CH_CFG_USE_SEMAPHORES"
#endif

#if (CH_CFG_FACTORY_MAILBOXES == TRUE) && (CH_CFG_USE_MAILBOXES == FALSE)
#error "CH_CFG_FACTORY_MAILBOXES requires CH_CFG_USE_MAILBOXES"
#endif

#if (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) && (CH_CFG_USE_OBJ_FIFOS == FALSE)
#error "CH_CFG_FACTORY_OBJ_FIFOS requires CH_CFG_USE_OBJ_FIFOS"
#endif

/*===========================================================================*/
/* Module data structures and types.                                         */
/*===========================================================================*/

/**
 * @brief   Type of a dynamic object list element.
 */
typedef struct ch_dyn_element {
  /**
   * @brief   Next dynamic object in the list.
   */
  struct ch_dyn_element *next;
  /**
   * @brief   Number of references to this object.
   */
  ucnt_t                refs;
#if (CH_CFG_FACTORY_MAX_NAMES_LENGTH > 0) || defined(__DOXYGEN__)
  char                  name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
#else
  const char            *name;
#endif
} dyn_element_t;

/**
 * @brief   Type of a dynamic object list.
 */
typedef struct ch_dyn_list {
    dyn_element_t       *next;
} dyn_list_t;

#if (CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Type of a registered object.
 */
typedef struct ch_registered_static_object {
  /**
   * @brief   List element of the registered object.
   */
  dyn_element_t         element;
  /**
   * @brief   Pointer to the object.
   * @note    The type of the object is not stored in anyway.
   */
  void                  *objp;
} registered_object_t;
#endif

#if (CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Type of a dynamic buffer object.
 */
typedef struct ch_dyn_object {
  /**
   * @brief   List element of the dynamic buffer object.
   */
  dyn_element_t         element;
  /**
   * @brief   The buffer.
   * @note    This requires C99.
   */
  uint8_t               buffer[];
} dyn_buffer_t;
#endif

#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Type of a dynamic semaphore.
 */
typedef struct ch_dyn_semaphore {
  /**
   * @brief   List element of the dynamic semaphore.
   */
  dyn_element_t         element;
  /**
   * @brief   The semaphore.
   */
  semaphore_t           sem;
} dyn_semaphore_t;
#endif

#if (CH_CFG_FACTORY_MAILBOXES == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Type of a dynamic buffer object.
 */
typedef struct ch_dyn_mailbox {
  /**
   * @brief   List element of the dynamic buffer object.
   */
  dyn_element_t         element;
  /**
   * @brief   The mailbox.
   */
  mailbox_t             mbx;
  /**
   * @brief   Messages buffer.
   * @note    This requires C99.
   */
  msg_t                 msgbuf[];
} dyn_mailbox_t;
#endif

#if (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Type of a dynamic buffer object.
 */
typedef struct ch_dyn_objects_fifo {
  /**
   * @brief   List element of the dynamic buffer object.
   */
  dyn_element_t         element;
  /**
   * @brief   The objects FIFO.
   */
  objects_fifo_t        fifo;
  /**
   * @brief   Messages buffer.
   * @note    This open array is followed by another area containing the
   *          objects, this area is not represented in this structure.
   * @note    This requires C99.
   */
  msg_t                 msgbuf[];
} dyn_objects_fifo_t;
#endif

/**
 * @brief   Type of the factory main object.
 */
typedef struct ch_objects_factory {
  /**
   * @brief   List of the registered objects.
   */
  dyn_list_t            obj_list;
  /**
   * @brief   Pool of the available registered objects.
   */
  memory_pool_t         obj_pool;
#if (CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || defined(__DOXYGEN__)
  /**
   * @brief   List of the allocated buffer objects.
   */
  dyn_list_t            buf_list;
#endif /* CH_CFG_FACTORY_GENERIC_BUFFERS = TRUE */
#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
  /**
   * @brief   List of the allocated semaphores.
   */
  dyn_list_t            sem_list;
  /**
   * @brief   Pool of the available semaphores.
   */
  memory_pool_t         sem_pool;
#endif /* CH_CFG_FACTORY_SEMAPHORES = TRUE */
#if (CH_CFG_FACTORY_MAILBOXES == TRUE) || defined(__DOXYGEN__)
  /**
   * @brief   List of the allocated buffer objects.
   */
  dyn_list_t            mbx_list;
#endif /* CH_CFG_FACTORY_MAILBOXES = TRUE */
#if (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) || defined(__DOXYGEN__)
  /**
   * @brief   List of the allocated "objects FIFO" objects.
   */
  dyn_list_t            fifo_list;
#endif /* CH_CFG_FACTORY_OBJ_FIFOS = TRUE */
} objects_factory_t;

/*===========================================================================*/
/* Module macros.                                                            */
/*===========================================================================*/

/*===========================================================================*/
/* External declarations.                                                    */
/*===========================================================================*/

#if !defined(__DOXYGEN__)
extern objects_factory_t ch_factory;
#endif

#ifdef __cplusplus
extern "C" {
#endif
  void _factory_init(void);
#if (CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE) || defined(__DOXYGEN__)
  registered_object_t *chFactoryRegisterObject(const char *name,
                                                            void *objp);
  registered_object_t *chFactoryFindObject(const char *name);
  void chFactoryReleaseObject(registered_object_t *rop);
#endif
#if (CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || defined(__DOXYGEN__)
  dyn_buffer_t *chFactoryCreateBuffer(const char *name, size_t size);
  dyn_buffer_t *chFactoryFindBuffer(const char *name);
  void chFactoryReleaseBuffer(dyn_buffer_t *dbp);
#endif
#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
  dyn_semaphore_t *chFactoryCreateSemaphore(const char *name, cnt_t n);
  dyn_semaphore_t *chFactoryFindSemaphore(const char *name);
  void chFactoryReleaseSemaphore(dyn_semaphore_t *dsp);
#endif
#if (CH_CFG_FACTORY_MAILBOXES == TRUE) || defined(__DOXYGEN__)
  dyn_mailbox_t *chFactoryCreateMailbox(const char *name, size_t n);
  dyn_mailbox_t *chFactoryFindMailbox(const char *name);
  void chFactoryReleaseMailbox(dyn_mailbox_t *dmp);
#endif
#if (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) || defined(__DOXYGEN__)
  dyn_objects_fifo_t *chFactoryCreateObjectsFIFO(const char *name,
                                                 size_t objsize,
                                                 size_t objn,
                                                 unsigned objalign);
  dyn_objects_fifo_t *chFactoryFindObjectsFIFO(const char *name);
  void chFactoryReleaseObjectsFIFO(dyn_objects_fifo_t *dofp);
#endif
#ifdef __cplusplus
}
#endif

/*===========================================================================*/
/* Module inline functions.                                                  */
/*===========================================================================*/

/**
 * @brief   Duplicates an object reference.
 * @note    This function can be used on any kind of dynamic object.
 *
 * @param[in] dep       pointer to the element field of the object
 * @return              The duplicated object reference.
 *
 * @iclass
 */
static inline dyn_element_t *chFactoryDuplicateReferenceI(dyn_element_t *dep) {

  chDbgCheckClassI();

  dep->refs++;

  return dep;
}

#if (CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Returns the size of a generic dynamic buffer object.
 *
 * @param[in] dbp       dynamic buffer object reference
 * @return              The size of the buffer object in bytes.
 *
 * @api
 */
static inline size_t chFactoryGetBufferSize(dyn_buffer_t *dbp) {

  return chHeapGetSize(dbp) - sizeof (dyn_element_t);
}
#endif

#endif /* CH_CFG_USE_FACTORY == TRUE */

#endif /* CHFACTORY_H */

/** @} */