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
This commit is contained in:
Giovanni Di Sirio 2019-08-25 13:27:36 +00:00
parent 5b0a0fe5b0
commit 107296cd78
5 changed files with 103 additions and 87 deletions

View File

@ -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

View File

@ -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"
/*===========================================================================*/

View File

@ -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,

View File

@ -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

View File

@ -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 <tt>sizeof (oc_object_t)</tt>.
* @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);
}