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