/*
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 chfactory.c
* @brief ChibiOS objects factory and registry code.
*
* @addtogroup objects_factory
* @details The object factory is a subsystem that allows to:
* - Register static objects by name.
* - Dynamically 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"
#if (CH_CFG_USE_FACTORY == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*
* Defaults on the best synchronization mechanism available.
*/
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
#define F_LOCK() chMtxLock(&ch_factory.mtx)
#define F_UNLOCK() chMtxUnlock(&ch_factory.mtx)
#else
#define F_LOCK() (void) chSemWait(&ch_factory.sem)
#define F_UNLOCK() chSemSignal(&ch_factory.sem)
#endif
/*===========================================================================*/
/* 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(const char *name, dyn_list_t *dlp) {
dyn_element_t *p = dlp->next;
while (p != (dyn_element_t *)dlp) {
if (strncmp(p->name, name, CH_CFG_FACTORY_MAX_NAMES_LENGTH) == 0) {
return p;
}
p = p->next;
}
return NULL;
}
static dyn_element_t *dyn_list_unlink(dyn_element_t *element,
dyn_list_t *dlp) {
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;
}
#if CH_FACTORY_REQUIRES_HEAP || defined(__DOXYGEN__)
static dyn_element_t *dyn_create_object_heap(const char *name,
dyn_list_t *dlp,
size_t size) {
dyn_element_t *dep;
chDbgCheck(name != NULL);
/* Checking if an object with this name has already been created.*/
dep = dyn_list_find(name, dlp);
if (dep != NULL) {
return NULL;
}
/* Allocating space for the new buffer object.*/
/*lint -save -e668 [] Lint is confused by the above chDbgCheck() and
incorrectly assumes that strncpy() could receive a NULL pointer.*/
dep = (dyn_element_t *)chHeapAlloc(NULL, size);
if (dep == NULL) {
return NULL;
}
/* Initializing object list element.*/
strncpy(dep->name, name, CH_CFG_FACTORY_MAX_NAMES_LENGTH);
/*lint -restore*/
dep->refs = (ucnt_t)1;
dep->next = dlp->next;
/* Updating factory list.*/
dlp->next = dep;
return dep;
}
static void dyn_release_object_heap(dyn_element_t *dep,
dyn_list_t *dlp) {
chDbgCheck(dep != NULL);
chDbgAssert(dep->refs > (ucnt_t)0, "invalid references number");
dep->refs--;
if (dep->refs == (ucnt_t)0) {
dep = dyn_list_unlink(dep, dlp);
chHeapFree((void *)dep);
}
}
#endif /* CH_FACTORY_REQUIRES_HEAP */
#if CH_FACTORY_REQUIRES_POOLS || defined(__DOXYGEN__)
static dyn_element_t *dyn_create_object_pool(const char *name,
dyn_list_t *dlp,
memory_pool_t *mp) {
dyn_element_t *dep;
chDbgCheck(name != NULL);
/* Checking if an object object with this name has already been created.*/
dep = dyn_list_find(name, dlp);
if (dep != NULL) {
return NULL;
}
/* Allocating space for the new object.*/
dep = (dyn_element_t *)chPoolAlloc(mp);
if (dep == NULL) {
return NULL;
}
/* Initializing object list element.*/
/*lint -save -e668 [] Lint is confused by the above chDbgCheck() and
incorrectly assumes that strncpy() could receive a NULL pointer.*/
strncpy(dep->name, name, CH_CFG_FACTORY_MAX_NAMES_LENGTH);
/*lint -restore*/
dep->refs = (ucnt_t)1;
dep->next = dlp->next;
/* Updating factory list.*/
dlp->next = (dyn_element_t *)dep;
return dep;
}
static void dyn_release_object_pool(dyn_element_t *dep,
dyn_list_t *dlp,
memory_pool_t *mp) {
chDbgCheck(dep != NULL);
chDbgAssert(dep->refs > (ucnt_t)0, "invalid references number");
dep->refs--;
if (dep->refs == (ucnt_t)0) {
dep = dyn_list_unlink(dep, dlp);
chPoolFree(mp, (void *)dep);
}
}
#endif /* CH_FACTORY_REQUIRES_POOLS */
static dyn_element_t *dyn_find_object(const char *name, dyn_list_t *dlp) {
dyn_element_t *dep;
chDbgCheck(name != NULL);
/* Checking if an object with this name has already been created.*/
dep = dyn_list_find(name, dlp);
if (dep != NULL) {
/* Increasing references counter.*/
dep->refs++;
}
return dep;
}
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes the objects factory.
*
* @init
*/
void _factory_init(void) {
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
chMtxObjectInit(&ch_factory.mtx);
#else
chSemObjectInit(&ch_factory.sem, (cnt_t)1);
#endif
#if CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE
dyn_list_init(&ch_factory.obj_list);
chPoolObjectInit(&ch_factory.obj_pool,
sizeof (registered_object_t),
chCoreAllocAlignedI);
#endif
#if CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE
dyn_list_init(&ch_factory.buf_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_MAILBOXES == TRUE
dyn_list_init(&ch_factory.mbx_list);
#endif
#if CH_CFG_FACTORY_OBJ_FIFOS == TRUE
dyn_list_init(&ch_factory.fifo_list);
#endif
}
#if (CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE) || defined(__DOXIGEN__)
/**
* @brief Registers a generic object.
* @post A reference to the registered object is returned and the
* reference counter is initialized to one.
*
* @param[in] name name to be assigned to the registered object
* @param[in] objp pointer to the object to be registered
*
* @return The reference to the registered object.
* @retval NULL if the object to be registered cannot be allocated or
* a registered object with the same name exists.
*
* @api
*/
registered_object_t *chFactoryRegisterObject(const char *name,
void *objp) {
registered_object_t *rop;
F_LOCK();
rop = (registered_object_t *)dyn_create_object_pool(name,
&ch_factory.obj_list,
&ch_factory.obj_pool);
if (rop != NULL) {
/* Initializing registered object data.*/
rop->objp = objp;
}
F_UNLOCK();
return rop;
}
/**
* @brief Retrieves a registered object.
* @post A reference to the registered object is returned with the
* reference counter increased by one.
*
* @param[in] name name of the registered object
*
* @return The reference to the found registered object.
* @retval NULL if a registered object with the specified name
* does not exist.
*
* @api
*/
registered_object_t *chFactoryFindObject(const char *name) {
registered_object_t *rop;
F_LOCK();
rop = (registered_object_t *)dyn_find_object(name, &ch_factory.obj_list);
F_UNLOCK();
return rop;
}
/**
* @brief Retrieves a registered object by pointer.
* @post A reference to the registered object is returned with the
* reference counter increased by one.
*
* @param[in] objp pointer to the object to be retrieved
*
* @return The reference to the found registered object.
* @retval NULL if a registered object with the specified pointer
* does not exist.
*
* @api
*/
registered_object_t *chFactoryFindObjectByPointer(void *objp) {
registered_object_t *rop = (registered_object_t *)ch_factory.obj_list.next;
F_LOCK();
while ((void *)rop != (void *)&ch_factory.obj_list) {
if (rop->objp == objp) {
rop->element.refs++;
F_UNLOCK();
return rop;
}
rop = (registered_object_t *)rop->element.next;
}
F_UNLOCK();
return NULL;
}
/**
* @brief Releases a registered object.
* @details The reference counter of the registered object is decreased
* by one, if reaches zero then the registered object memory
* is freed.
* @note The object itself is not freed, it could be static, only the
* allocated list element is freed.
*
* @param[in] rop registered object reference
*
* @api
*/
void chFactoryReleaseObject(registered_object_t *rop){
F_LOCK();
dyn_release_object_pool(&rop->element,
&ch_factory.obj_list,
&ch_factory.obj_pool);
F_UNLOCK();
}
#endif /* CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE */
#if (CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a generic dynamic buffer object.
* @post A reference to the dynamic buffer object is returned and the
* reference counter is initialized to one.
* @post The dynamic buffer object is filled with zeros.
*
* @param[in] name name to be assigned to the new dynamic buffer object
* @param[in] size payload size of the dynamic buffer object to be created
*
* @return The reference to the created dynamic buffer object.
* @retval NULL if the dynamic buffer object cannot be allocated or
* a dynamic buffer object with the same name exists.
*
* @api
*/
dyn_buffer_t *chFactoryCreateBuffer(const char *name, size_t size) {
dyn_buffer_t *dbp;
F_LOCK();
dbp = (dyn_buffer_t *)dyn_create_object_heap(name,
&ch_factory.buf_list,
size);
if (dbp != NULL) {
/* Initializing buffer object data.*/
memset((void *)dbp->buffer, 0, size);
}
F_UNLOCK();
return dbp;
}
/**
* @brief Retrieves a dynamic buffer object.
* @post A reference to the dynamic buffer object is returned with the
* reference counter increased by one.
*
* @param[in] name name of the dynamic buffer object
*
* @return The reference to the found dynamic buffer object.
* @retval NULL if a dynamic buffer object with the specified name
* does not exist.
*
* @api
*/
dyn_buffer_t *chFactoryFindBuffer(const char *name) {
dyn_buffer_t *dbp;
F_LOCK();
dbp = (dyn_buffer_t *)dyn_find_object(name, &ch_factory.buf_list);
F_UNLOCK();
return dbp;
}
/**
* @brief Releases a dynamic buffer object.
* @details The reference counter of the dynamic buffer object is decreased
* by one, if reaches zero then the dynamic buffer object memory
* is freed.
*
* @param[in] dbp dynamic buffer object reference
*
* @api
*/
void chFactoryReleaseBuffer(dyn_buffer_t *dbp) {
F_LOCK();
dyn_release_object_heap(&dbp->element, &ch_factory.buf_list);
F_UNLOCK();
}
#endif /* CH_CFG_FACTORY_GENERIC_BUFFERS = TRUE */
#if (CH_CFG_FACTORY_SEMAPHORES == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a dynamic semaphore object.
* @post A reference to the dynamic semaphore object is returned and the
* reference counter is initialized to one.
* @post The dynamic semaphore object is initialized and ready to use.
*
* @param[in] name name to be assigned to the new dynamic semaphore object
* @param[in] n dynamic semaphore object counter initialization value
*
* @return The reference to the created dynamic semaphore object.
* @retval NULL if the dynamic semaphore object cannot be allocated or
* a dynamic semaphore with the same name exists.
*
* @api
*/
dyn_semaphore_t *chFactoryCreateSemaphore(const char *name, cnt_t n) {
dyn_semaphore_t *dsp;
F_LOCK();
dsp = (dyn_semaphore_t *)dyn_create_object_pool(name,
&ch_factory.sem_list,
&ch_factory.sem_pool);
if (dsp != NULL) {
/* Initializing semaphore object dataa.*/
chSemObjectInit(&dsp->sem, n);
}
F_UNLOCK();
return dsp;
}
/**
* @brief Retrieves a dynamic semaphore object.
* @post A reference to the dynamic semaphore object is returned with the
* reference counter increased by one.
*
* @param[in] name name of the dynamic semaphore object
*
* @return The reference to the found dynamic semaphore object.
* @retval NULL if a dynamic semaphore object with the specified name
* does not exist.
*
* @api
*/
dyn_semaphore_t *chFactoryFindSemaphore(const char *name) {
dyn_semaphore_t *dsp;
F_LOCK();
dsp = (dyn_semaphore_t *)dyn_find_object(name, &ch_factory.sem_list);
F_UNLOCK();
return dsp;
}
/**
* @brief Releases a dynamic semaphore object.
* @details The reference counter of the dynamic semaphore object is decreased
* by one, if reaches zero then the dynamic semaphore object memory
* is freed.
*
* @param[in] dsp dynamic semaphore object reference
*
* @api
*/
void chFactoryReleaseSemaphore(dyn_semaphore_t *dsp) {
F_LOCK();
dyn_release_object_pool(&dsp->element,
&ch_factory.sem_list,
&ch_factory.sem_pool);
F_UNLOCK();
}
#endif /* CH_CFG_FACTORY_SEMAPHORES = TRUE */
#if (CH_CFG_FACTORY_MAILBOXES == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a dynamic mailbox object.
* @post A reference to the dynamic mailbox object is returned and the
* reference counter is initialized to one.
* @post The dynamic mailbox object is initialized and ready to use.
*
* @param[in] name name to be assigned to the new dynamic mailbox object
* @param[in] n mailbox buffer size as number of messages
*
* @return The reference to the created dynamic mailbox object.
* @retval NULL if the dynamic mailbox object cannot be allocated or
* a dynamic mailbox object with the same name exists.
*
* @api
*/
dyn_mailbox_t *chFactoryCreateMailbox(const char *name, size_t n) {
dyn_mailbox_t *dmp;
F_LOCK();
dmp = (dyn_mailbox_t *)dyn_create_object_heap(name,
&ch_factory.mbx_list,
sizeof (dyn_mailbox_t) +
(n * sizeof (msg_t)));
if (dmp != NULL) {
/* Initializing mailbox object data.*/
chMBObjectInit(&dmp->mbx, dmp->msgbuf, n);
}
F_UNLOCK();
return dmp;
}
/**
* @brief Retrieves a dynamic mailbox object.
* @post A reference to the dynamic mailbox object is returned with the
* reference counter increased by one.
*
* @param[in] name name of the dynamic mailbox object
*
* @return The reference to the found dynamic mailbox object.
* @retval NULL if a dynamic mailbox object with the specified name
* does not exist.
*
* @api
*/
dyn_mailbox_t *chFactoryFindMailbox(const char *name) {
dyn_mailbox_t *dmp;
F_LOCK();
dmp = (dyn_mailbox_t *)dyn_find_object(name, &ch_factory.mbx_list);
F_UNLOCK();
return dmp;
}
/**
* @brief Releases a dynamic mailbox object.
* @details The reference counter of the dynamic mailbox object is decreased
* by one, if reaches zero then the dynamic mailbox object memory
* is freed.
*
* @param[in] dmp dynamic mailbox object reference
*
* @api
*/
void chFactoryReleaseMailbox(dyn_mailbox_t *dmp) {
F_LOCK();
dyn_release_object_heap(&dmp->element, &ch_factory.mbx_list);
F_UNLOCK();
}
#endif /* CH_CFG_FACTORY_MAILBOXES = TRUE */
#if (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) || defined(__DOXIGEN__)
/**
* @brief Creates a dynamic "objects FIFO" object.
* @post A reference to the dynamic "objects FIFO" object is returned and
* the reference counter is initialized to one.
* @post The dynamic "objects FIFO" object is initialized and ready to use.
*
* @param[in] name name to be assigned to the new dynamic "objects FIFO"
* object
* @param[in] objsize size of objects
* @param[in] objn number of objects available
* @param[in] objalign required objects alignment
* @return The reference to the created dynamic "objects FIFO"
* object.
* @retval NULL if the dynamic "objects FIFO" object cannot be
* allocated or a dynamic "objects FIFO" object with
* the same name exists.
*
* @api
*/
dyn_objects_fifo_t *chFactoryCreateObjectsFIFO(const char *name,
size_t objsize,
size_t objn,
unsigned objalign) {
dyn_objects_fifo_t *dofp;
F_LOCK();
dofp = (dyn_objects_fifo_t *)dyn_create_object_heap(name,
&ch_factory.fifo_list,
sizeof (dyn_objects_fifo_t) +
(objn * sizeof (msg_t)) +
(objn * objsize));
if (dofp != NULL) {
/* Initializing mailbox object data.*/
chFifoObjectInit(&dofp->fifo, objsize, objn, objalign,
(void *)&dofp->msgbuf[objn], dofp->msgbuf);
}
F_UNLOCK();
return dofp;
}
/**
* @brief Retrieves a dynamic "objects FIFO" object.
* @post A reference to the dynamic "objects FIFO" object is returned with
* the reference counter increased by one.
*
* @param[in] name name of the dynamic "objects FIFO" object
*
* @return The reference to the found dynamic "objects FIFO"
* object.
* @retval NULL if a dynamic "objects FIFO" object with the specified
* name does not exist.
*
* @api
*/
dyn_objects_fifo_t *chFactoryFindObjectsFIFO(const char *name) {
dyn_objects_fifo_t *dofp;
F_LOCK();
dofp = (dyn_objects_fifo_t *)dyn_find_object(name, &ch_factory.fifo_list);
F_UNLOCK();
return dofp;
}
/**
* @brief Releases a dynamic "objects FIFO" object.
* @details The reference counter of the dynamic "objects FIFO" object is
* decreased by one, if reaches zero then the dynamic "objects FIFO"
* object memory is freed.
*
* @param[in] dofp dynamic "objects FIFO" object reference
*
* @api
*/
void chFactoryReleaseObjectsFIFO(dyn_objects_fifo_t *dofp) {
F_LOCK();
dyn_release_object_heap(&dofp->element, &ch_factory.fifo_list);
F_UNLOCK();
}
#endif /* CH_CFG_FACTORY_MAILBOXES = TRUE */
#endif /* CH_CFG_USE_FACTORY == TRUE */
/** @} */
id='n567' href='#n567'>567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
|