/*
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 .
*/
/**
* @file chfactory.c
* @brief ChibiOS objects factory code.
*
* @addtogroup objects_factory
* @details The object factory is a subsystem that allows to:
* - Create objects and assign them a name.
* - Retrieve existing objects by name.
* - Free objects by reference.
* .
* Allocated OS objects are handled using a reference counter, only
* when all references have been released then the object memory is
* freed in a pool.
* @pre This subsystem requires the @p CH_CFG_USE_MEMCORE and
* @p CH_CFG_USE_MEMPOOLS options to be set to @p TRUE. The
* option @p CH_CFG_USE_HEAP is also required if the support
* for variable length objects is enabled.
* @note Compatible with RT and NIL.
* @{
*/
#include
#include "ch.h"
#include "chfactory.h"
#if (CH_CFG_USE_FACTORY == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/**
* @brief Factory object static instance.
* @note It is a global object because it could be accessed through
* a specific debugger plugin.
*/
objects_factory_t ch_factory;
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
static inline void dyn_list_init(dyn_list_t *dlp) {
dlp->next = (dyn_element_t *)dlp;
}
static dyn_element_t *dyn_list_find(dyn_list_t *dlp, const char *name) {
dyn_element_t *p = dlp->next;
while (p != (dyn_element_t *)dlp) {
if (strncmp(p->name, name, CH_CFG_FACTORY_MAX_NAMES_LENGHT) == 0) {
return p;
}
p = p->next;
}
return NULL;
}
static dyn_element_t *dyn_list_unlink(dyn_list_t *dlp, dyn_element_t *element) {
dyn_element_t *prev = (dyn_element_t *)dlp;
/* Scanning the list.*/
while (prev->next != (dyn_element_t *)dlp) {
if (prev->next == element) {
/* Found.*/
prev->next = element->next;
return element;
}
/* Next element in the list.*/
prev = prev->next;
}
return NULL;
}
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes the objects factory.
*
* @init
*/
void _factory_init(void) {
#if CH_CFG_FACTORY_GENERIC_BUFFER == TRUE
dyn_list_init(&ch_factory.obj_list);
#endif
#if CH_CFG_FACTORY_SEMAPHORES == TRUE
dyn_list_init(&ch_factory.sem_list);
chPoolObjectInit(&ch_factory.sem_pool,
sizeof (dyn_semaphore_t),
chCoreAllocAlignedI);
#endif
}
#if (CH_CFG_FACTORY_GENERIC_BUFFER == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a generic dynamic buffer object.
* @post A reference to the buffer object is returned and the reference
* counter is initialized to one.
* @post The buffer object is zero filled.
*
* @param[in] name name to be assigned to the new buffer object
* @param[in] size payload size of the buffer object to be created
*
* @return The reference to the created buffer object.
* @retval NULL if the buffer object cannot be allocated or a buffer
* object with the same name exists.
*
* @api
*/
dyn_buffer_t *chFactoryCreateBuffer(const char *name, size_t size) {
dyn_buffer_t *dbp;
chDbgCheck(name != NULL);
chSysLock();
/* Checking if a buffer object with this name has already been created.*/
dbp = (dyn_buffer_t *)dyn_list_find(&ch_factory.obj_list, name);
if (dbp != NULL) {
/* Object exists, error.*/
chSysUnlock();
return NULL;
}
/* Allocating space for the new buffer object.*/
dbp = chHeapAlloc(NULL, size);
if (dbp == NULL) {
chSysUnlock();
return NULL;
}
/* Initializing buffer object data and metadata.*/
strncpy(dbp->element.name, name, CH_CFG_FACTORY_MAX_NAMES_LENGHT);
dbp->element.refs = 1;
dbp->element.next = ch_factory.obj_list.next;
memset((void *)dbp->buffer, 0, size);
/* Updating factory list.*/
ch_factory.obj_list.next = (dyn_element_t *)dbp;
chSysUnlock();
return dbp;
}
/**
* @brief Retrieves a generic dynamic buffer object.
* @post A reference to the buffer object is returned with the reference
* counter increased by one.
*
* @param[in] name name to be assigned to the new buffer object
*
* @return The reference to the found buffer object.
* @retval NULL if a buffer object with the specified name name does
* not exist.
*
* @api
*/
dyn_buffer_t *chFactoryFindBuffer(const char *name) {
dyn_buffer_t *dbp;
chDbgCheck(name != NULL);
chSysLock();
/* Checking if a buffer object with this name has already been created.*/
dbp = (dyn_buffer_t *)dyn_list_find(&ch_factory.obj_list, name);
if (dbp == NULL) {
/* The buffer object does not exists, error.*/
chSysUnlock();
return NULL;
}
/* Increasing references counter.*/
dbp->element.refs += 1;
chSysUnlock();
return dbp;
}
/**
* @brief Releases a generic dynamic buffer object.
* @details The reference counter of the buffer object is decreased by one, if
* reaches zero then the buffer object memory is freed.
*
* @param[in] dbp generic buffer object reference
*
* @api
*/
void chFactoryReleaseBuffer(dyn_buffer_t *dbp) {
chDbgCheck(dbp != NULL);
chSysLock();
chDbgAssert(dbp->element.refs > 0U, "invalid references number");
dbp = (dyn_buffer_t *)dyn_list_unlink(&ch_factory.obj_list,
&dbp->element);
chDbgAssert(dbp != NULL, "invalid reference passed");
dbp->element.refs--;
if (dbp->element.refs == 0) {
chHeapFree((void *)dbp);
}
chSysUnlock();
}
#endif /* CH_CFG_FACTORY_GENERIC_BUFFER = TRUE */
#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a dynamic semaphore object.
* @post A reference to the semaphore object is returned and the reference
* counter is initialized to one.
* @post The semaphore object is initialized and ready to use.
*
* @param[in] name name to be assigned to the new semaphore object
* @param[in] n semaphore object counter initialization value
*
* @return The reference to the created semaphore object.
* @retval NULL if the semaphore object cannot be allocated or a
* semaphore with the same name exists.
*
* @api
*/
dyn_semaphore_t *chFactoryCreateSemaphore(const char *name, cnt_t n) {
dyn_semaphore_t *dsp;
chDbgCheck(name != NULL);
chSysLock();
/* Checking if a semaphore object with this name has already been created.*/
dsp = (dyn_semaphore_t *)dyn_list_find(&ch_factory.sem_list, name);
if (dsp != NULL) {
/* The semaphore object exists, error.*/
chSysUnlock();
return NULL;
}
/* Allocating space for the new semaphore object.*/
dsp = chCoreAlloc(sizeof (dyn_semaphore_t));
if (dsp == NULL) {
chSysUnlock();
return NULL;
}
/* Initializing semaphore object data and metadata.*/
strncpy(dsp->element.name, name, CH_CFG_FACTORY_MAX_NAMES_LENGHT);
dsp->element.refs = 1;
dsp->element.next = ch_factory.obj_list.next;
chSemObjectInit(&dsp->sem, n);
/* Updating factory list.*/
ch_factory.obj_list.next = (dyn_element_t *)dsp;
chSysUnlock();
return dsp;
}
/**
* @brief Retrieves a generic dynamic semaphore object.
* @post A reference to the semaphore object is returned with the reference
* counter increased by one.
*
* @param[in] name name to be assigned to the new semaphore object
*
* @return The reference to the found semaphore object.
* @retval NULL if a semaphore object with the specified name name does
* not exist.
*
* @api
*/
dyn_semaphore_t *chFactoryFindSemaphore(const char *name) {
dyn_semaphore_t *dsp;
chDbgCheck(name != NULL);
chSysLock();
/* Checking if a semaphore object with this name has already been created.*/
dsp = (dyn_semaphore_t *)dyn_list_find(&ch_factory.obj_list, name);
if (dsp == NULL) {
/* The semaphore object does not exists, error.*/
chSysUnlock();
return NULL;
}
/* Increasing references counter.*/
dsp->element.refs += 1;
chSysUnlock();
return dsp;
}
/**
* @brief Releases a semaphore dynamic object.
* @details The reference counter of the semaphore object is decreased by one,
* if reaches zero then the semaphore object memory is freed.
*
* @param[in] dsp semaphore object reference
*
* @api
*/
void chFactoryReleaseSemaphore(dyn_semaphore_t *dsp) {
chDbgCheck(dsp != NULL);
chSysLock();
chDbgAssert(dsp->element.refs > 0U, "invalid references number");
dsp = (dyn_semaphore_t *)dyn_list_unlink(&ch_factory.sem_list,
&dsp->element);
chDbgAssert(dsp != NULL, "invalid reference passed");
dsp->element.refs--;
if (dsp->element.refs == 0) {
chPoolFree(&ch_factory.sem_pool, (void *)dsp);
}
chSysUnlock();
}
#endif /* CH_CFG_FACTORY_SEMAPHORES = TRUE */
#endif /* CH_CFG_USE_FACTORY == TRUE */
/** @} */