From 107296cd788e7afb94c82743155492e8507eeef1 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sun, 25 Aug 2019 13:27:36 +0000 Subject: [PATCH] Cache almost complete, tests to be created. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12957 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- .../STM32/RT-STM32L476-DISCOVERY/cfg/chconf.h | 11 ++ os/oslib/include/chlib.h | 10 +- os/oslib/include/chobjcaches.h | 32 +++-- os/oslib/oslib.mk | 4 + os/oslib/src/chobjcaches.c | 133 ++++++++---------- 5 files changed, 103 insertions(+), 87 deletions(-) diff --git a/demos/STM32/RT-STM32L476-DISCOVERY/cfg/chconf.h b/demos/STM32/RT-STM32L476-DISCOVERY/cfg/chconf.h index e50f15cce..f760fa476 100644 --- a/demos/STM32/RT-STM32L476-DISCOVERY/cfg/chconf.h +++ b/demos/STM32/RT-STM32L476-DISCOVERY/cfg/chconf.h @@ -381,6 +381,17 @@ #define CH_CFG_USE_PIPES TRUE #endif +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + /** * @brief Dynamic Threads APIs. * @details If enabled then the dynamic threads creation APIs are included diff --git a/os/oslib/include/chlib.h b/os/oslib/include/chlib.h index d8cd6a313..ed3080def 100644 --- a/os/oslib/include/chlib.h +++ b/os/oslib/include/chlib.h @@ -52,7 +52,7 @@ /** * @brief OS Library version string. */ -#define CH_OSLIB_VERSION "1.1.0" +#define CH_OSLIB_VERSION "1.2.0" /** * @brief OS Library version major number. @@ -62,7 +62,7 @@ /** * @brief OS Library version minor number. */ -#define CH_OSLIB_MINOR 1 +#define CH_OSLIB_MINOR 2 /** * @brief OS Library version patch number. @@ -108,6 +108,11 @@ #error "CH_CFG_USE_PIPES not defined in chconf.h" #endif +#if !defined(CH_CFG_USE_OBJ_CACHES) +//#error "CH_CFG_USE_OBJ_CACHES not defined in chconf.h" +#define CH_CFG_USE_OBJ_CACHES 0 +#endif + /* Objects factory options checks.*/ #if !defined(CH_CFG_USE_FACTORY) #error "CH_CFG_USE_FACTORY not defined in chconf.h" @@ -210,6 +215,7 @@ #include "chmempools.h" #include "chobjfifos.h" #include "chpipes.h" +#include "chobjcaches.h" #include "chfactory.h" /*===========================================================================*/ diff --git a/os/oslib/include/chobjcaches.h b/os/oslib/include/chobjcaches.h index 6515fb73d..db225d268 100644 --- a/os/oslib/include/chobjcaches.h +++ b/os/oslib/include/chobjcaches.h @@ -41,16 +41,11 @@ #define OC_FLAG_INLRU 0x00000001U #define OC_FLAG_INHASH 0x00000002U #define OC_FLAG_SHARED 0x00000004U -#define OC_FLAG_NOTREAD 0x00000008U +#define OC_FLAG_NOTSYNC 0x00000008U #define OC_FLAG_LAZYWRITE 0x00000010U #define OC_FLAG_FORGET 0x00000020U /** @} */ -/** - * @brief Identifier for an invalid group. - */ -#define OC_NO_GROUP 0xFFFFFFFFU - /*===========================================================================*/ /* Module pre-compile time settings. */ /*===========================================================================*/ @@ -185,11 +180,15 @@ struct ch_oc_object { */ oc_flags_t obj_flags; /** - * @brief Pointer to the data part of the object. - * @note This pointer must be initialized outside this module after - * calling @p chCacheObjectInit() which sets it to @p NULL. + * @brief User pointer. + * @note This pointer can be used to refer to external buffers, + * @p chCacheObjectInit() initializes it to @p NULL. */ - void *data; + void *dptr; + /** + * @brief Embedded data as an open array. + */ + uint8_t dbuf[]; }; /** @@ -199,7 +198,7 @@ struct ch_objects_cache { /** * @brief Number of elements in the hash table. */ - size_t hashn; + ucnt_t hashn; /** * @brief Pointer to the hash table. */ @@ -207,11 +206,15 @@ struct ch_objects_cache { /** * @brief Number of elements in the objects table. */ - size_t objn; + ucnt_t objn; + /** + * @brief Size of elements in the objects table. + */ + size_t objsz; /** * @brief Pointer to the objects table. */ - oc_object_t *objp; + void *objvp; /** * @brief LRU list header. */ @@ -249,7 +252,8 @@ extern "C" { ucnt_t hashn, oc_hash_header_t *hashp, ucnt_t objn, - oc_object_t *objp, + size_t objsz, + void *objvp, oc_readf_t readf, oc_writef_t writef); oc_object_t *chCacheGetObject(objects_cache_t *ocp, diff --git a/os/oslib/oslib.mk b/os/oslib/oslib.mk index 6f837c0b2..9122f7706 100644 --- a/os/oslib/oslib.mk +++ b/os/oslib/oslib.mk @@ -29,6 +29,9 @@ endif ifneq ($(findstring CH_CFG_USE_PIPES TRUE,$(CHLIBCONF)),) LIBSRC += $(CHIBIOS)/os/oslib/src/chpipes.c endif +ifneq ($(findstring CH_CFG_USE_OBJ_CACHES TRUE,$(CHLIBCONF)),) +LIBSRC += $(CHIBIOS)/os/oslib/src/chobjcaches.c +endif ifneq ($(findstring CH_CFG_USE_FACTORY TRUE,$(CHLIBCONF)),) LIBSRC += $(CHIBIOS)/os/oslib/src/chfactory.c endif @@ -38,6 +41,7 @@ LIBSRC := $(CHIBIOS)/os/oslib/src/chmboxes.c \ $(CHIBIOS)/os/oslib/src/chmemheaps.c \ $(CHIBIOS)/os/oslib/src/chmempools.c \ $(CHIBIOS)/os/oslib/src/chpipes.c \ + $(CHIBIOS)/os/oslib/src/chobjcaches.c \ $(CHIBIOS)/os/oslib/src/chfactory.c endif diff --git a/os/oslib/src/chobjcaches.c b/os/oslib/src/chobjcaches.c index dd7c5f731..31187da05 100644 --- a/os/oslib/src/chobjcaches.c +++ b/os/oslib/src/chobjcaches.c @@ -229,41 +229,36 @@ static oc_object_t *lru_get_last_s(objects_cache_t *ocp) { * @param[in] hashp pointer to the hash table as an array of * @p oc_hash_header_t * @param[in] objn number of elements in the objects table array + * @param[in] objsz size of elements in the objects table array, the + * minimum value is sizeof (oc_object_t). * @param[in] hashp pointer to the hash objects as an array of * @p oc_object_t * @param[in] readf pointer to an object reader function * @param[in] writef pointer to an object writer function * - * Object records states: - * - Invalid not owned: - * (OC_FLAG_INLRU, cnt==1). - * - Caching an object not owned: - * (OC_FLAG_INLRU, OC_FLAG_INHASH, OC_FLAG_CACHEHIT, cnt==1). - * - Representing an object owned: - * (OC_FLAG_INHASH, cnt<=0). - * - Caching an object owned: - * (OC_FLAG_INHASH, OC_FLAG_CACHEHIT, cnt<=0). - * * @init */ void chCacheObjectInit(objects_cache_t *ocp, ucnt_t hashn, oc_hash_header_t *hashp, ucnt_t objn, - oc_object_t *objp, + size_t objsz, + void *objvp, oc_readf_t readf, oc_writef_t writef) { - chDbgCheck((ocp != NULL) && (hashp != NULL) && (objp != NULL) && + chDbgCheck((ocp != NULL) && (hashp != NULL) && (objvp != NULL) && ((hashn & (hashn - 1U)) == 0U) && - (objn > (size_t)0) && (hashn >= objn)); + (objn > (size_t)0) && (hashn >= objn) && + (objsz >= sizeof (oc_object_t)) && + ((objsz & (PORT_NATURAL_ALIGN - 1U)) == 0U)); chSemObjectInit(&ocp->cache_sem, (cnt_t)1); chSemObjectInit(&ocp->lru_sem, (cnt_t)objn); ocp->hashn = hashn; ocp->hashp = hashp; ocp->objn = objn; - ocp->objp = objp; + ocp->objvp = objvp; ocp->readf = readf; ocp->writef = writef; ocp->lru.hash_next = NULL; @@ -272,34 +267,37 @@ void chCacheObjectInit(objects_cache_t *ocp, ocp->lru.lru_prev = (oc_object_t *)&ocp->lru; /* Hash headers initialization.*/ - while (hashp < &ocp->hashp[ocp->hashn]) { + do { hashp->hash_next = (oc_object_t *)hashp; hashp->hash_prev = (oc_object_t *)hashp; - } + hashp++; + } while (hashp < &ocp->hashp[ocp->hashn]); /* Object headers initialization.*/ - while (objp < &ocp->objp[ocp->objn]) { + do { + oc_object_t *objp = (oc_object_t *)objvp; + chSemObjectInit(&objp->obj_sem, (cnt_t)1); LRU_INSERT_HEAD(ocp, objp); objp->obj_group = 0U; objp->obj_key = 0U; objp->obj_flags = OC_FLAG_INLRU; - objp->data = NULL; - } + objp->dptr = NULL; + objvp += objsz; + objn--; + } while (objn > 0U); } /** * @brief Retrieves an object from the cache. * @note If the object is not in cache then the returned object is marked - * as @p OC_FLAG_NOTREAD meaning that its data contains garbage and + * as @p OC_FLAG_NOTSYNC meaning that its data contains garbage and * must be initialized. * * @param[in] ocp pointer to the @p objects_cache_t structure - * @param[in] group object group identifier or @p OC_NO_GROUP if - * requesting a generic object buffer + * @param[in] group object group identifier * @param[in] key object identifier within the group * @return The pointer to the retrieved object. - * @retval NULL is a reserved value. * * @api */ @@ -311,56 +309,49 @@ oc_object_t *chCacheGetObject(objects_cache_t *ocp, /* Critical section enter, the hash check operation is fast.*/ chSysLock(); - /* If the requested object is not a generic one.*/ - if (group == OC_NO_GROUP) { - /* Any buffer will do.*/ - objp = NULL; /* TODO */ - } - else { - /* Checking the cache for a hit.*/ - objp = hash_get_s(ocp, group, key); + /* Checking the cache for a hit.*/ + objp = hash_get_s(ocp, group, key); - chDbgAssert((objp->obj_flags & OC_FLAG_INHASH) == OC_FLAG_INHASH, - "not in hash"); + chDbgAssert((objp->obj_flags & OC_FLAG_INHASH) == OC_FLAG_INHASH, + "not in hash"); - if (objp != NULL) { - /* Cache hit, checking if the buffer is owned by some - other thread.*/ - if (chSemGetCounterI(&objp->obj_sem) > (cnt_t)0) { - /* Not owned case, it is in the LRU list.*/ + if (objp != NULL) { + /* Cache hit, checking if the buffer is owned by some + other thread.*/ + if (chSemGetCounterI(&objp->obj_sem) > (cnt_t)0) { + /* Not owned case, it is in the LRU list.*/ - chDbgAssert((objp->obj_flags & OC_FLAG_INLRU) == OC_FLAG_INLRU, - "not in LRU"); + chDbgAssert((objp->obj_flags & OC_FLAG_INLRU) == OC_FLAG_INLRU, + "not in LRU"); - /* Removing the object from LRU, now it is "owned".*/ - LRU_REMOVE(objp); - objp->obj_flags &= ~OC_FLAG_INLRU; + /* Removing the object from LRU, now it is "owned".*/ + LRU_REMOVE(objp); + objp->obj_flags &= ~OC_FLAG_INLRU; - /* Getting the object semaphore, we know there is no wait so - using the "fast" variant.*/ - chSemFastWaitI(&objp->obj_sem); - } - else { - /* Owned case, some other thread is playing with this object, we - need to wait.*/ - - chDbgAssert((objp->obj_flags & OC_FLAG_INLRU) == 0U, "in LRU"); - - /* Waiting on the buffer semaphore.*/ - chSemWaitS(&objp->obj_sem); - } + /* Getting the object semaphore, we know there is no wait so + using the "fast" variant.*/ + chSemFastWaitI(&objp->obj_sem); } else { - /* Cache miss, getting an object buffer from the LRU list.*/ - objp = lru_get_last_s(ocp); + /* Owned case, some other thread is playing with this object, we + need to wait.*/ - /* Naming this object and publishing it in the hash table.*/ - objp->obj_group = group; - objp->obj_key = key; - objp->obj_flags = OC_FLAG_INHASH | OC_FLAG_NOTREAD; - HASH_INSERT(ocp, objp, group, key); + chDbgAssert((objp->obj_flags & OC_FLAG_INLRU) == 0U, "in LRU"); + + /* Waiting on the buffer semaphore.*/ + chSemWaitS(&objp->obj_sem); } } + else { + /* Cache miss, getting an object buffer from the LRU list.*/ + objp = lru_get_last_s(ocp); + + /* Naming this object and publishing it in the hash table.*/ + objp->obj_group = group; + objp->obj_key = key; + objp->obj_flags = OC_FLAG_INHASH | OC_FLAG_NOTSYNC; + HASH_INSERT(ocp, objp, group, key); + } /* Out of critical section and returning the object.*/ chSysUnlock(); @@ -374,7 +365,7 @@ oc_object_t *chCacheGetObject(objects_cache_t *ocp, * - @p OC_FLAG_INLRU must be cleared. * - @p OC_FLAG_INHASH must be set. * - @p OC_FLAG_SHARED must be cleared. - * - @p OC_FLAG_NOTREAD invalidates the object and queues it on + * - @p OC_FLAG_NOTSYNC invalidates the object and queues it on * the LRU tail. * - @p OC_FLAG_LAZYWRITE is ignored and kept, a write will occur * when the object is removed from the LRU list (lazy write). @@ -400,19 +391,19 @@ void chCacheReleaseObjectI(objects_cache_t *ocp, handed directly without going through the LRU.*/ if (chSemGetCounterI(&objp->obj_sem) < (cnt_t)0) { /* Clearing all flags except those that are still meaningful, note, - OC_FLAG_NOTREAD and OC_FLAG_LAZYWRITE are passed, the other thread + OC_FLAG_NOTSYNC and OC_FLAG_LAZYWRITE are passed, the other thread will handle them.*/ - objp->obj_flags &= OC_FLAG_INHASH | OC_FLAG_NOTREAD | OC_FLAG_LAZYWRITE; + objp->obj_flags &= OC_FLAG_INHASH | OC_FLAG_NOTSYNC | OC_FLAG_LAZYWRITE; chSemSignalI(&objp->obj_sem); return; } - /* If the object specifies OC_FLAG_NOTREAD then it must be invalidated + /* If the object specifies OC_FLAG_NOTSYNC then it must be invalidated and removed from the hash table.*/ - if ((objp->obj_flags & OC_FLAG_NOTREAD) != 0U) { + if ((objp->obj_flags & OC_FLAG_NOTSYNC) != 0U) { HASH_REMOVE(objp); LRU_INSERT_TAIL(ocp, objp); - objp->obj_group = OC_NO_GROUP; + objp->obj_group = 0U; objp->obj_key = 0U; objp->obj_flags = OC_FLAG_INLRU; } @@ -458,10 +449,10 @@ bool chCacheReadObject(objects_cache_t *ocp, oc_object_t *objp, bool async) { - /* Marking it as OC_FLAG_NOTREAD because the read operation is going + /* Marking it as OC_FLAG_NOTSYNC because the read operation is going to corrupt it in case of failure. It is responsibility of the read implementation to clear it if the operation succeeds.*/ - objp->obj_flags |= OC_FLAG_NOTREAD; + objp->obj_flags |= OC_FLAG_NOTSYNC; return ocp->readf(ocp, objp, async); }