mirror of
https://github.com/openharmony/drivers_framework.git
synced 2026-08-27 10:51:15 -04:00
3016511bde
Signed-off-by: YOUR_NAME <guodongqi2@huawei.com>
190 lines
5.9 KiB
C
190 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
|
|
*
|
|
* HDF is dual licensed: you can use it either under the terms of
|
|
* the GPL, or the BSD license, at your option.
|
|
* See the LICENSE file in the root of this repository for complete details.
|
|
*/
|
|
|
|
#include "hdf_object_alloc.h"
|
|
#include "hdf_slist.h"
|
|
#include "osal_mutex.h"
|
|
|
|
struct HdfChunkLink {
|
|
uint32_t buffSize;
|
|
uint8_t *buffer;
|
|
};
|
|
|
|
struct HdfObjectNode {
|
|
struct HdfSListNode entry;
|
|
uint32_t chunkCount;
|
|
uint32_t freeCount;
|
|
uint32_t chunkSize;
|
|
struct HdfChunkLink **chunkStack;
|
|
};
|
|
|
|
struct HdfObjectAlloc {
|
|
struct HdfSList nodes;
|
|
struct OsalMutex mutex;
|
|
bool isConstructed;
|
|
};
|
|
static const unsigned int ALIGN_MASK = 3;
|
|
#define ALIGN4(x) (uint32_t)(((uintptr_t)(x) + ALIGN_MASK) & (~ALIGN_MASK))
|
|
|
|
#define OBJECT_NODE_SIZE sizeof(struct ObjectNode)
|
|
#define OBJECT_CHUNK_COOKIE_SIZE (sizeof(struct ChunkLink) + sizeof(void *))
|
|
|
|
void HdfObjectAllocConstruct(struct HdfObjectAlloc *alloc)
|
|
{
|
|
HdfSListInit(&alloc->nodes);
|
|
OsalMutexInit(&alloc->mutex);
|
|
alloc->isConstructed = true;
|
|
}
|
|
struct HdfObjectAlloc *HdfObjectAllocGetInstance()
|
|
{
|
|
static struct HdfObjectAlloc instance = { 0 };
|
|
|
|
if (!instance.isConstructed) {
|
|
HdfObjectAllocConstruct(&instance);
|
|
}
|
|
|
|
return &instance;
|
|
}
|
|
|
|
struct HdfObjectNode *HdfObjectAllocFindSuitableChunk(
|
|
struct HdfObjectAlloc *alloc, size_t size)
|
|
{
|
|
struct HdfSListIterator it;
|
|
struct HdfObjectNode *bestFitNode = NULL;
|
|
struct HdfObjectNode *objectNode = NULL;
|
|
HdfSListIteratorInit(&it, &alloc->nodes);
|
|
|
|
while (HdfSListIteratorHasNext(&it)) {
|
|
objectNode = (struct HdfObjectNode *)HdfSListIteratorNext(&it);
|
|
if (size == objectNode->chunkSize) {
|
|
bestFitNode = objectNode;
|
|
break;
|
|
} else if (size < objectNode->chunkSize) {
|
|
bestFitNode = objectNode;
|
|
}
|
|
}
|
|
|
|
return bestFitNode;
|
|
}
|
|
|
|
static void HdfObjectAllocPushObjectNode(
|
|
struct HdfObjectAlloc *alloc, struct HdfObjectNode *node)
|
|
{
|
|
struct HdfSListIterator it;
|
|
struct HdfObjectNode *objectNode = NULL;
|
|
HdfSListIteratorInit(&it, &alloc->nodes);
|
|
|
|
while (HdfSListIteratorHasNext(&it)) {
|
|
objectNode = (struct HdfObjectNode *)HdfSListIteratorNext(&it);
|
|
if (node->chunkSize >= objectNode->chunkSize) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
HdfSListIteratorInsert(&it, &node->entry);
|
|
}
|
|
|
|
static void HdfObjectAllocPreloadChunk(
|
|
void *chunkBuf, uint32_t buffSize, uint32_t chunkSize)
|
|
{
|
|
struct HdfObjectAlloc *allocator = HdfObjectAllocGetInstance();
|
|
|
|
if (buffSize > OBJECT_NODE_SIZE) {
|
|
uint32_t idx;
|
|
struct ChunkLink *chunkLink;
|
|
struct ObjectNode *node;
|
|
uint32_t alignedSize = ALIGN4(chunkSize);
|
|
uint32_t alignedBufSize = ALIGN4(buffSize);
|
|
uint32_t blockSize = alignedSize + sizeof(struct ChunkLink);
|
|
uint8_t *alignedBuff = (uint8_t *)(uintptr_t)ALIGN4(chunkBuf);
|
|
node = (struct ObjectNode *)(alignedBuff + alignedBufSize - OBJECT_NODE_SIZE);
|
|
node->freeCount = 0;
|
|
node->chunkSize = alignedSize;
|
|
node->chunkCount = ((uint8_t *)node - alignedBuff) / (blockSize + sizeof(void *));
|
|
node->chunkStack = (struct ChunkLink **)(alignedBuff + node->chunkCount * blockSize);
|
|
|
|
for (idx = 0; idx < node->chunkCount; idx++) {
|
|
chunkLink = (struct ChunkLink *)&alignedBuff[idx * blockSize];
|
|
chunkLink->buffSize = node->chunkSize;
|
|
node->chunkStack[node->freeCount++] = chunkLink;
|
|
chunkLink->buffer = (uint8_t *)(chunkLink + 1);
|
|
}
|
|
|
|
HdfObjectAllocPushObjectNode(allocator, node);
|
|
}
|
|
}
|
|
|
|
void HdfObjectAllocLoadConfigs(const struct HdfObjectPoolConfig *configs)
|
|
{
|
|
uint32_t idx;
|
|
char *chunkBuffBegin = configs->buffer;
|
|
char *chunkBuffEnd = configs->buffer + configs->bufferSize;
|
|
|
|
for (idx = 0; (idx < configs->numChunks) && (chunkBuffBegin < chunkBuffEnd); idx++) {
|
|
const struct ObjectChunkConfig *chunkConfig = &configs->chunks[idx];
|
|
size_t chunkBufSize = OBJECT_NODE_SIZE + \
|
|
(OBJECT_CHUNK_COOKIE_SIZE + chunkConfig->chunkSize) * chunkConfig->chunkCount;
|
|
|
|
if (chunkBuffBegin + chunkBufSize <= chunkBuffEnd) {
|
|
HdfObjectAllocPreloadChunk(chunkBuffBegin, chunkBufSize, chunkConfig->chunkSize);
|
|
}
|
|
|
|
chunkBuffBegin += chunkBufSize;
|
|
}
|
|
}
|
|
|
|
void HdfObjectAllocInit()
|
|
{
|
|
const struct HdfObjectPoolConfig *config = HdfObjectAllocGetConfig();
|
|
|
|
if (config != NULL) {
|
|
HdfObjectAllocLoadConfigs(config);
|
|
}
|
|
}
|
|
|
|
void *HdfObjectAllocAlloc(size_t size)
|
|
{
|
|
struct HdfChunkLink *chunkLink = NULL;
|
|
struct HdfObjectNode *objectNode = NULL;
|
|
struct HdfObjectAlloc *allocator = HdfObjectAllocGetInstance();
|
|
OsalMutexLock(&allocator->mutex);
|
|
objectNode = HdfObjectAllocFindSuitableChunk(allocator, size);
|
|
if ((objectNode != NULL) && (objectNode->freeCount == 0)) {
|
|
goto finished;
|
|
}
|
|
|
|
if (objectNode->freeCount > objectNode->chunkCount) {
|
|
if (objectNode->freeCount > objectNode->chunkCount) {
|
|
}
|
|
}
|
|
|
|
chunkLink = (struct ChunkLink *)objectNode->chunkStack[--objectNode->freeCount];
|
|
finished:
|
|
OsalMutexUnlock(&allocator->mutex);
|
|
return chunkLink ? chunkLink->buffer : NULL;
|
|
}
|
|
|
|
void HdfObjectAllocFree(void *object)
|
|
{
|
|
struct HdfChunkLink *chunkLink = container_of(void, object, struct ChunkLink, buffer);
|
|
struct HdfObjectNode *objectNode = NULL;
|
|
struct HdfObjectAlloc *allocator = HdfObjectAllocGetInstance();
|
|
OsalMutexLock(&allocator->mutex);
|
|
objectNode = HdfObjectAllocFindSuitableChunk(allocator, chunkLink->buffSize);
|
|
if (objectNode != NULL) {
|
|
objectNode->chunkStack[objectNode->freeCount++] = chunkLink;
|
|
|
|
if (objectNode->freeCount > objectNode->chunkCount) {
|
|
HDF_LOGE("exception: count,free:%d,total %d", objectNode->freeCount, objectNode->chunkCount);
|
|
}
|
|
}
|
|
|
|
OsalMutexUnlock(&allocator->mutex);
|
|
}
|
|
|