Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Rentz-Reichert2019-05-10 05:05:44 -0400
committerGerrit Code Review @ Eclipse.org2019-05-10 05:05:44 -0400
commit877c88575ff8a7665aa78107a2b03d0ce0bbfb07 (patch)
tree0628b685ab1386a0d4b3eb251db1e1f47c6adaef
parentf7590cbfbde3879099cd9ee78efc5e0c8c24b7ad (diff)
parent0347fa1887a7042769517eb14b432637680f6b56 (diff)
downloadorg.eclipse.etrice-877c88575ff8a7665aa78107a2b03d0ce0bbfb07.tar.gz
org.eclipse.etrice-877c88575ff8a7665aa78107a2b03d0ce0bbfb07.tar.xz
org.eclipse.etrice-877c88575ff8a7665aa78107a2b03d0ce0bbfb07.zip
Merge "Bug 546770 - improve and complete memory management"
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory.h13
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.c63
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.h17
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.c194
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.h45
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.c104
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.h53
-rw-r--r--runtime/org.eclipse.etrice.runtime.c/src/common/osal/etLock.h42
-rw-r--r--tests/org.eclipse.etrice.runtime.c.tests/src/runtime/TestEtMemory.c103
9 files changed, 531 insertions, 103 deletions
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory.h b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory.h
index 2b960e259..13a9faee9 100644
--- a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory.h
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory.h
@@ -38,12 +38,23 @@ typedef void* etMemory_alloc(struct etMemory* heap, etUInt16 size);
* \param obj pointer to the memory returned
* \param size the size in bytes of the memory returned
*/
-typedef void etMemory_free(struct etMemory* heap, void* obj, etUInt16 size);
+typedef void etMemory_free(struct etMemory* heap, void* obj);
+
+typedef struct etMemoryStatistics {
+ const char* name;
+ etUInt32 maxUsed;
+ etUInt32 nFailingRequests;
+ struct etMemoryStatistics* next;
+}
+etMemoryStatistics;
typedef struct etMemory {
/** size of the heap in bytes */
etUInt32 size;
+ /** statistical data made available through the runtime */
+ etMemoryStatistics statistics;
+
/** the configured allocation method */
etMemory_alloc* alloc;
/** the configured freeing method */
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.c b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.c
index bcd5f0501..99485173b 100644
--- a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.c
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.c
@@ -16,13 +16,26 @@
#include "debugging/etMSCLogger.h"
+#define DO_LOCK \
+ if (self->lock!=NULL) { \
+ self->lock->lockFct(self->lock->lockData); \
+ }
+
+#define DO_UNLOCK \
+ if (self->lock!=NULL) { \
+ self->lock->unlockFct(self->lock->lockData); \
+ }
+
+#define GET_USED (etQueue_getSize(&self->blockPool) * self->blockSize)
+
typedef struct etFixedSizeMemory {
etMemory base;
- etUInt8 *buffer;
- etUInt16 maxBlocks;
- etUInt16 blockSize;
- etQueue blockPool;
+ etUInt8 *buffer; /**< the heap to be allocated from */
+ etUInt16 maxBlocks; /**< the maximum number of blocks */
+ etUInt16 blockSize; /**< block size */
+ etQueue blockPool; /**< pool of free blocks */
+ etLock* lock; /**< user supplied lock functions */
} etFixedSizeMemory;
@@ -31,24 +44,36 @@ void* etMemory_FixedSize_alloc(etMemory* heap, etUInt16 size) {
void* mem = NULL;
size = MEM_CEIL(size);
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "alloc")
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FixedSize", "alloc")
+ DO_LOCK
if (size<=self->blockSize){
if (self->blockPool.size>0) {
+ etUInt32 used;
mem = etQueue_pop(&self->blockPool);
+ used = GET_USED;
+ if (used > self->base.statistics.maxUsed) {
+ self->base.statistics.maxUsed = used;
+ }
}
}
+ if (mem==NULL) {
+ self->base.statistics.nFailingRequests++;
+ }
+ DO_UNLOCK
ET_MSC_LOGGER_SYNC_EXIT
return mem;
}
-void etMemory_FixedSize_free(etMemory* heap, void* obj, etUInt16 size) {
+void etMemory_FixedSize_free(etMemory* heap, void* obj) {
etFixedSizeMemory* self = (etFixedSizeMemory*) heap;
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "free")
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FixedSize", "free")
+ DO_LOCK
etQueue_push(&self->blockPool, obj);
+ DO_UNLOCK
ET_MSC_LOGGER_SYNC_EXIT
}
@@ -61,9 +86,11 @@ etMemory* etMemory_FixedSize_init(void* heap, etUInt32 size, etUInt16 blockSize)
size_t data_size = MEM_CEIL(sizeof(etFixedSizeMemory));
int i;
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "init")
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FixedSize", "init")
self->base.size = size;
+ self->base.statistics.maxUsed = 0;
+ self->base.statistics.nFailingRequests = 0;
self->base.alloc = etMemory_FixedSize_alloc;
self->base.free = etMemory_FixedSize_free;
@@ -84,3 +111,23 @@ etMemory* etMemory_FixedSize_init(void* heap, etUInt32 size, etUInt16 blockSize)
return &self->base;
}
+
+void etMemory_FixedSize_setUserLock(etMemory* mem, etLock* lock) {
+ etFixedSizeMemory* self = (etFixedSizeMemory*) mem;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FixedSize", "setUserLock")
+ self->lock = lock;
+ ET_MSC_LOGGER_SYNC_EXIT
+}
+
+etUInt32 etMemory_FixedSize_getFreeHeapMem(etMemory* mem) {
+ etFixedSizeMemory* self = (etFixedSizeMemory*) mem;
+ etUInt32 result;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FixedSize", "getFreeHeapMem")
+
+ DO_LOCK
+ result = GET_USED;
+ DO_UNLOCK
+
+ ET_MSC_LOGGER_SYNC_EXIT
+ return result;
+}
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.h b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.h
index 855f3e53f..04558bf7a 100644
--- a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.h
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FixedSize.h
@@ -23,6 +23,7 @@
#include "base/etMemory.h"
#include "base/etQueue.h"
+#include "osal/etLock.h"
/**
* initializes the heap with a simple block management
@@ -35,4 +36,20 @@
*/
etMemory* etMemory_FixedSize_init(void* heap, etUInt32 size, etUInt16 blockSize);
+/**
+ * supply optional user lock/unlock functions for usage in a multi-threaded environment.
+ * \param mem pointer to the memory management struct
+ * \lock pointer to a user supplied locking struct
+ */
+void etMemory_FixedSize_setUserLock(etMemory* mem, etLock* lock);
+
+/**
+ * determines and returns the free memory of the heap
+ *
+ * \param mem pointer to the heap to be managed
+ *
+ * \return the free memory of the heap
+ */
+etUInt32 etMemory_FixedSize_getFreeHeapMem(etMemory* mem);
+
#endif /* _ETMEMORY_FIXED_SIZE_H_ */
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.c b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.c
index 09e2008ab..008acb047 100644
--- a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.c
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.c
@@ -14,8 +14,19 @@
#include "debugging/etLogger.h"
#include "debugging/etMSCLogger.h"
-#define UNUSED_LIST 0
+#define UNUSED_LIST 0
#define DEBUG_FREE_LISTS 1
+#define OBJ_OFFSET etALIGNMENT
+
+#define DO_LOCK \
+ if (self->lock!=NULL) { \
+ self->lock->lockFct(self->lock->lockData); \
+ }
+
+#define DO_UNLOCK \
+ if (self->lock!=NULL) { \
+ self->lock->unlockFct(self->lock->lockData); \
+ }
typedef struct etFreeListObj {
struct etFreeListObj* next;
@@ -35,30 +46,49 @@ typedef struct etFreeListMemory {
etMemory base; /** the "base class" */
etUInt8* current; /**< next free position on the heap */
etUInt16 nslots; /**< number of free lists */
+ etLock* lock; /**< user supplied lock functions */
+ roundUpSize* roundUp; /**< rounding method (identity by default) */
etFreeListInfo freelists[1]; /**< array of free list infos (array used with size nslots) */
} etFreeListMemory;
/*
* private functions
*/
-static void* etMemory_getHeapMem(etFreeListMemory* self, etUInt16 size) {
+static void* etMemory_FreeList_getHeapMem(etFreeListMemory* self, etUInt16 size) {
etUInt8* obj = NULL;
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "getHeapListMem")
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList", "getHeapListMem")
if (self->current + size < ((etUInt8*)self) + self->base.size)
{
- obj = self->current;
+ etUInt32 used;
+
+ // store size in the first bytes
+ *((etUInt16*)self->current) = size;
+
+ // object pointer at offset
+ obj = self->current + OBJ_OFFSET;
+
+ // shift current
self->current += size;
+
+ used = ((etUInt8*)self) + self->base.size - self->current;
+ if (used > self->base.statistics.maxUsed) {
+ self->base.statistics.maxUsed = used;
+ }
+ }
+
+ if (obj==NULL) {
+ self->base.statistics.nFailingRequests++;
}
ET_MSC_LOGGER_SYNC_EXIT
return obj;
}
-static void* etMemory_getFreeListMem(etFreeListMemory* self, etUInt16 size) {
+static void* etMemory_FreeList_getFreeListMem(etFreeListMemory* self, etUInt16 size) {
etUInt8* mem = NULL;
int asize, slot_offset, slot, slot_size;
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "getFreeListMem")
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList", "getFreeListMem")
asize = (size / etALIGNMENT);
for (slot_offset = 0; slot_offset < self->nslots; slot_offset++) {
@@ -82,10 +112,11 @@ static void* etMemory_getFreeListMem(etFreeListMemory* self, etUInt16 size) {
return mem;
}
-static void etMemory_putFreeListMem(etFreeListMemory* self, void* obj, etUInt16 size) {
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "putFreeListMem")
+static void etMemory_FreeList_putFreeListMem(etFreeListMemory* self, void* obj) {
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList", "putFreeListMem")
{
int asize, slot_offset, slot, slot_size;
+ etUInt16 size = *((etUInt16*) (((etUInt8*) obj) - OBJ_OFFSET));
asize = (size / etALIGNMENT);
for (slot_offset = 0; slot_offset < self->nslots; slot_offset++) {
@@ -115,84 +146,149 @@ static void etMemory_putFreeListMem(etFreeListMemory* self, void* obj, etUInt16
ET_MSC_LOGGER_SYNC_EXIT
}
-void* etMemory_FreeList_alloc(etMemory* heap, etUInt16 size) {
+static void* etMemory_FreeList_alloc(etMemory* heap, etUInt16 size) {
+ etFreeListMemory* self = (etFreeListMemory*) heap;
void* mem;
- size = MEM_CEIL(size);
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "alloc")
- mem = etMemory_getFreeListMem((etFreeListMemory*) heap, size);
- if (mem==NULL)
- mem = etMemory_getHeapMem((etFreeListMemory*) heap, size);
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList", "alloc")
+
+ // rounded required size + space to store the size
+ size = MEM_CEIL(self->roundUp(size) + OBJ_OFFSET);
+
+ DO_LOCK
+ mem = etMemory_FreeList_getFreeListMem((etFreeListMemory*) heap, size);
+ if (mem==NULL) {
+ mem = etMemory_FreeList_getHeapMem((etFreeListMemory*) heap, size);
+ }
+ DO_UNLOCK
ET_MSC_LOGGER_SYNC_EXIT
return mem;
}
-void etMemory_FreeList_free(etMemory* heap, void* obj, etUInt16 size) {
- ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "free")
- {
- size = MEM_CEIL(size);
- etMemory_putFreeListMem((etFreeListMemory*) heap, obj, size);
- }
+static void etMemory_FreeList_free(etMemory* heap, void* obj) {
+ etFreeListMemory* self = (etFreeListMemory*) heap;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList", "free")
+
+ DO_LOCK
+ etMemory_FreeList_putFreeListMem(self, obj);
+ DO_UNLOCK
+
ET_MSC_LOGGER_SYNC_EXIT
}
+static etUInt16 etMemory_FreeList_identity(etUInt16 size) {
+ return size;
+}
+
+etUInt16 etMemory_FreeList_power2(etUInt16 v) {
+ /* https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v++;
+ return v;
+}
+
+
/*
* the public interface
*/
etMemory* etMemory_FreeList_init(void* heap, etUInt32 size, etUInt16 nslots) {
etFreeListMemory* self = (etFreeListMemory*) heap;
ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList_init", "init")
+ int data_size = MEM_CEIL(sizeof(etFreeListMemory)+(nslots-1)*sizeof(etFreeListInfo));
+ etMemory* result = NULL;
- self->base.size = size;
- self->base.alloc = etMemory_FreeList_alloc;
- self->base.free = etMemory_FreeList_free;
- self->nslots = nslots;
- {
- int used = sizeof(etFreeListMemory)+(self->nslots-1)*sizeof(etFreeListInfo);
- self->current = ((etUInt8*)self)+MEM_CEIL(used);
- }
+ if (size > data_size) {
+ self->base.size = size;
+ self->base.statistics.maxUsed = 0;
+ self->base.statistics.nFailingRequests = 0;
+ self->base.alloc = etMemory_FreeList_alloc;
+ self->base.free = etMemory_FreeList_free;
+ self->roundUp = etMemory_FreeList_identity;
+ self->lock = NULL;
+ self->nslots = nslots;
+ self->current = ((etUInt8*) self) + data_size;
- /* initialize the free lists */
- {
- int i;
- for (i=0; i<self->nslots; ++i)
- self->freelists[i].objsize = UNUSED_LIST;
+ /* initialize the free lists */
+ {
+ int i;
+ for (i=0; i<self->nslots; ++i)
+ self->freelists[i].objsize = UNUSED_LIST;
+ }
+
+ result = &self->base;
}
+
ET_MSC_LOGGER_SYNC_EXIT
+ return result;
+}
- return &self->base;
+void etMemory_FreeList_setUserLock(etMemory* mem, etLock* lock) {
+ etFreeListMemory* self = (etFreeListMemory*) mem;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList_init", "setUserLock")
+ self->lock = lock;
+ ET_MSC_LOGGER_SYNC_EXIT
}
-etUInt32 etMemory_FreeList_freeHeapMem(void* heap) {
- etFreeListMemory* self = (etFreeListMemory*) heap;
- return ((etUInt8*)self)+self->base.size - self->current;
+void etMemory_FreeList_setUserRounding(etMemory* mem, roundUpSize* roundup) {
+ etFreeListMemory* self = (etFreeListMemory*) mem;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_FreeList_init", "setUserRounding")
+ self->roundUp = roundup;
+ ET_MSC_LOGGER_SYNC_EXIT
}
-etUInt16 etMemory_FreeList_freeSlots(void* heap) {
- etFreeListMemory* self = (etFreeListMemory*) heap;
+etUInt32 etMemory_FreeList_getFreeHeapMem(etMemory* mem) {
+ etFreeListMemory* self = (etFreeListMemory*) mem;
+
+ DO_LOCK
+ etUInt32 result = ((etUInt8*) self) + self->base.size - self->current;
+ DO_UNLOCK
+
+ return result;
+}
+
+etUInt16 etMemory_FreeList_freeSlots(etMemory* mem) {
+ etFreeListMemory* self = (etFreeListMemory*) mem;
etUInt16 free = 0;
int slot;
+ DO_LOCK
for (slot=0; slot<self->nslots; ++slot)
if (self->freelists[slot].objsize==UNUSED_LIST)
++free;
+ DO_UNLOCK
return free;
}
-etUInt16 etMemory_FreeList_nObjects(void* heap, etUInt16 slot) {
+etUInt16 etMemory_FreeList_nObjects(etMemory* mem, etUInt16 slot) {
+ etUInt16 result = 0;
#if DEBUG_FREE_LISTS
- etFreeListMemory* self = (etFreeListMemory*) heap;
- if (slot<self->nslots)
- return self->freelists[slot].nobjects;
+ etFreeListMemory* self = (etFreeListMemory*) mem;
+ DO_LOCK
+ if (slot<self->nslots) {
+ result = self->freelists[slot].nobjects;
+ }
+ DO_UNLOCK
#endif
- return 0;
+ return result;
}
-etUInt16 etMemory_FreeList_sizeObjects(void* heap, etUInt16 slot) {
- etFreeListMemory* self = (etFreeListMemory*) heap;
- if (slot<self->nslots)
- return self->freelists[slot].objsize;
- return 0;
+etUInt16 etMemory_FreeList_sizeObjects(etMemory* mem, etUInt16 slot) {
+ etFreeListMemory* self = (etFreeListMemory*) mem;
+ etUInt16 result = 0;
+ DO_LOCK
+ if (slot<self->nslots) {
+ result = self->freelists[slot].objsize - OBJ_OFFSET;
+ }
+ DO_UNLOCK
+ return result;
+}
+
+etUInt16 etMemory_FreeList_MgmtDataPerObject() {
+ return OBJ_OFFSET;
}
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.h b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.h
index ff2806593..25cac9926 100644
--- a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.h
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_FreeList.h
@@ -21,6 +21,14 @@
* \author Henrik Rentz-Reichert
*/
#include "base/etMemory.h"
+#include "osal/etLock.h"
+
+typedef etUInt16 roundUpSize(etUInt16 size);
+
+/**
+ * this function rounds up to the next highest power of 2
+ */
+etUInt16 etMemory_FreeList_power2(etUInt16 v);
/**
* initializes the free list memory management on the given heap
@@ -34,42 +42,63 @@
etMemory* etMemory_FreeList_init(void* heap, etUInt32 size, etUInt16 nslots);
/**
+ * supply optional user lock/unlock functions for usage in a multi-threaded environment.
+ * \param mem pointer to the memory management struct
+ * \lock pointer to a user supplied locking struct
+ */
+void etMemory_FreeList_setUserLock(etMemory* mem, etLock* lock);
+
+/**
+ * by default the requested size is just rounded up to the next alignment boundary.
+ * In this case for every new size a slot is used. To use less slots at the cost of some 'wasted' memory
+ * the user can supply an optional round-up method to create less equivalence classes of object sized
+ * and thus reduce the number of slots needed.
+ * An alternative is to use etMemory_FreeList_power2().
+ */
+void etMemory_FreeList_setUserRounding(etMemory* mem, roundUpSize* roundup);
+
+/**
* determines and returns the free memory of the heap
*
- * \param heap pointer to the heap to be managed
+ * \param mem pointer to the heap to be managed
*
* \return the free memory of the heap
*/
-etUInt32 etMemory_FreeList_freeHeapMem(void* heap);
+etUInt32 etMemory_FreeList_getFreeHeapMem(etMemory* mem);
/**
* returns the number of objects in a given slot
*
- * \param heap pointer to the heap to be managed
+ * \param mem pointer to the heap to be managed
* \param slot the slot number
*
* \return the number of objects in a given slot or <code>0</code> if invalid slot
* or <code>DEBUG_FREE_LISTS</code> isn't <code>true</code>
*/
-etUInt16 etMemory_FreeList_nObjects(void* heap, etUInt16 slot);
+etUInt16 etMemory_FreeList_nObjects(etMemory* mem, etUInt16 slot);
/**
* returns the size of the objects in a given slot
*
- * \param heap pointer to the heap to be managed
+ * \param mem pointer to the heap to be managed
* \param slot the slot number
*
* \return the size of the objects in a given slot
*/
-etUInt16 etMemory_FreeList_sizeObjects(void* heap, etUInt16 slot);
+etUInt16 etMemory_FreeList_sizeObjects(etMemory* mem, etUInt16 slot);
/**
* returns the number of free slots
*
- * \param heap pointer to the heap to be managed
+ * \param mem pointer to the heap to be managed
*
* \return the number of free slots
*/
-etUInt16 etMemory_FreeList_freeSlots(void* heap);
+etUInt16 etMemory_FreeList_freeSlots(etMemory* mem);
+
+/**
+ * the size of the management data per allocated object
+ */
+etUInt16 etMemory_FreeList_MgmtDataPerObject();
#endif /* _ETMEMORY_FREE_LIST_H_ */
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.c b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.c
new file mode 100644
index 000000000..dc0efad8d
--- /dev/null
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.c
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2012 protos software gmbh (http://www.protos.de).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * CONTRIBUTORS:
+ * Henrik Rentz-Reichert (initial contribution)
+ *
+ *******************************************************************************/
+
+#include "base/etMemory_VariableSize.h"
+#include "base/etQueue.h"
+#include "debugging/etLogger.h"
+#include "debugging/etMSCLogger.h"
+
+
+#define DO_LOCK \
+ if (self->lock!=NULL) { \
+ self->lock->lockFct(self->lock->lockData); \
+ }
+
+#define DO_UNLOCK \
+ if (self->lock!=NULL) { \
+ self->lock->unlockFct(self->lock->lockData); \
+ }
+
+typedef struct etVariableSizeMemory {
+ etMemory base; /** the "base class" */
+
+ etUInt8* current; /**< next free position on the heap */
+ etLock* lock; /**< user supplied lock functions */
+} etVariableSizeMemory;
+
+
+void* etMemory_VariableSize_alloc(etMemory* heap, etUInt16 size) {
+ etVariableSizeMemory* self = (etVariableSizeMemory*) heap;
+ void* mem = NULL;
+ size = MEM_CEIL(size);
+
+ DO_LOCK
+ if (self->current + size < ((etUInt8*)self) + self->base.size) {
+ etUInt32 used;
+
+ mem = (void*) self->current;
+ self->current += size;
+
+ used = ((etUInt8*)self) + self->base.size - self->current;
+ if (used > self->base.statistics.maxUsed) {
+ self->base.statistics.maxUsed = used;
+ }
+ }
+ if (mem==NULL) {
+ self->base.statistics.nFailingRequests++;
+ }
+ DO_UNLOCK
+
+ ET_MSC_LOGGER_SYNC_EXIT
+ return mem;
+}
+
+void etMemory_VariableSize_free(etMemory* heap, void* obj) {
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "free")
+ /* do nothing */
+ ET_MSC_LOGGER_SYNC_EXIT
+}
+
+/*
+ * the public interface
+ */
+etMemory* etMemory_VariableSize_init(void* heap, etUInt32 size) {
+ etVariableSizeMemory* self = (etVariableSizeMemory*) heap;
+ size_t data_size = MEM_CEIL(sizeof(etVariableSizeMemory));
+ etMemory* result = NULL;
+
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory", "init")
+
+ if (size > data_size) {
+ self->base.size = size;
+ self->base.statistics.maxUsed = 0;
+ self->base.statistics.nFailingRequests = 0;
+ self->base.alloc = etMemory_VariableSize_alloc;
+ self->base.free = etMemory_VariableSize_free;
+
+ self->current = ((etUInt8*)self)+data_size;
+ result = &self->base;
+ }
+
+ ET_MSC_LOGGER_SYNC_EXIT
+ return result;
+}
+
+etUInt8 etMemory_VariableSize_freeHeapMem(etMemory* mem) {
+ etVariableSizeMemory* self = (etVariableSizeMemory*) mem;
+ return ((etUInt8*) self) + self->base.size - self->current;
+}
+
+void etMemory_VariableSize_setUserLock(etMemory* mem, etLock* lock) {
+ etVariableSizeMemory* self = (etVariableSizeMemory*) mem;
+ ET_MSC_LOGGER_SYNC_ENTRY("etMemory_VariableSize", "setUserLock")
+ self->lock = lock;
+ ET_MSC_LOGGER_SYNC_EXIT
+}
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.h b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.h
new file mode 100644
index 000000000..76e9d6a3c
--- /dev/null
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/base/etMemory_VariableSize.h
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2019 protos software gmbh (http://www.protos.de).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * CONTRIBUTORS:
+ * Henrik Rentz-Reichert (initial contribution)
+ *
+ *******************************************************************************/
+
+/**
+ * \file etMemory_VariableSize.h
+ *
+ * a simple memory management that uses equal sized chunks. The free chunks are maintained in
+ * a \ref etQueue
+ *
+ * \author Henrik Rentz-Reichert
+ */
+#ifndef _ETMEMORY_VARIABLE_SIZE_H_
+#define _ETMEMORY_VARIABLE_SIZE_H_
+
+#include "base/etMemory.h"
+#include "base/etQueue.h"
+#include "osal/etLock.h"
+
+/**
+ * initializes the heap with a simple block management
+ *
+ * \param heap pointer to the heap to be managed
+ * \param size the size in bytes of the heap
+ * \param blockSize the size of the (equal sized) blocks
+ *
+ * \return the pointer to the initialized etMemory struct
+ */
+etMemory* etMemory_VariableSize_init(void* heap, etUInt32 size);
+
+/**
+ * supply optional user lock/unlock functions for usage in a multi-threaded environment.
+ * \param mem pointer to the memory management struct
+ * \lock pointer to a user supplied locking struct
+ */
+void etMemory_VariableSize_setUserLock(etMemory* mem, etLock* lock);
+
+/**
+ * returns the free memory left in bytes
+ * \return the free memory left in bytes
+ */
+etUInt8 etMemory_VariableSize_freeHeapMem(etMemory* mem);
+
+
+#endif /* _ETMEMORY_VARIABLE_SIZE_H_ */
diff --git a/runtime/org.eclipse.etrice.runtime.c/src/common/osal/etLock.h b/runtime/org.eclipse.etrice.runtime.c/src/common/osal/etLock.h
new file mode 100644
index 000000000..98849f0fa
--- /dev/null
+++ b/runtime/org.eclipse.etrice.runtime.c/src/common/osal/etLock.h
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2013 protos software gmbh (http://www.protos.de).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * CONTRIBUTORS:
+ * Henrik Rentz-Reichert (initial contribution)
+ *
+ *
+ *******************************************************************************/
+
+/**
+ * \file etMutex.h
+ *
+ * etMutex.h defines a generic interface for platform specific implementations of a mutex
+ *
+ * \author Henrik Rentz-Reichert
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ETLOCK_H_
+#define _ETLOCK_H_
+
+typedef void etLock_lock(void* lockData);
+typedef void etLock_unlock(void* lockData);
+
+typedef struct etLock {
+ etLock_lock* lockFct;
+ etLock_unlock* unlockFct;
+ void* lockData;
+}
+etLock;
+
+#endif /* _ETLOCK_H_ */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/org.eclipse.etrice.runtime.c.tests/src/runtime/TestEtMemory.c b/tests/org.eclipse.etrice.runtime.c.tests/src/runtime/TestEtMemory.c
index f93239901..a0485936a 100644
--- a/tests/org.eclipse.etrice.runtime.c.tests/src/runtime/TestEtMemory.c
+++ b/tests/org.eclipse.etrice.runtime.c.tests/src/runtime/TestEtMemory.c
@@ -15,6 +15,7 @@
#include <stddef.h>
#include <string.h>
#include "etUnit/etUnit.h"
+#include "base/etMemory_VariableSize.h"
#include "base/etMemory_FixedSize.h"
#include "base/etMemory_FreeList.h"
@@ -37,6 +38,31 @@
#define SIZE6 96
+static void TestEtMemory_testVariableSize(etInt16 id) {
+ etUInt8 buffer[BUF_SIZE];
+ const etUInt16 blockSize = 2 * KBYTE;
+ const int nBlocks = BUF_SIZE / blockSize;
+ etMemory* mem = etMemory_VariableSize_init(buffer, BUF_SIZE);
+ int i;
+ void* obj;
+
+ EXPECT_TRUE(id, "mem!=NULL", mem!=NULL);
+
+ /* nBlocks-1 onjects can be allocated */
+ for (i=1; i<nBlocks; ++i) {
+ obj = mem->alloc(mem, blockSize);
+ if (obj==NULL) {
+ EXPECT_TRUE(id, "obj==NULL", ET_FALSE);
+ }
+ }
+
+ /* another block should fail */
+ obj = mem->alloc(mem, blockSize);
+ if (obj!=NULL) {
+ EXPECT_TRUE(id, "obj!=NULL", ET_FALSE);
+ }
+}
+
static void TestEtMemory_testFixedSize(etInt16 id) {
etUInt8 buffer[BUF_SIZE];
etUInt8* objects[TEST_BLOCKS];
@@ -52,7 +78,7 @@ static void TestEtMemory_testFixedSize(etInt16 id) {
memset(objects[i], i%4, TEST_BLOCK_SIZE);
}
for (i=0; i<TEST_BLOCKS/2; ++i) {
- mem->free(mem, objects[i*2], TEST_BLOCK_SIZE);
+ mem->free(mem, objects[i*2]);
}
for (i=0; i<TEST_BLOCKS/2; ++i) {
objects[i*2] = mem->alloc(mem, TEST_BLOCK_SIZE);
@@ -103,18 +129,44 @@ static void local_free(etInt16 id, etMemory* mem, etUInt8* objects[NSIZES][NOBJ]
for (kind=0; kind<NSIZES; ++kind) {
for (i=0; i<NOBJ; ++i) {
- mem->free(mem, objects[kind][i], sizes[kind]);
+ mem->free(mem, objects[kind][i]);
}
}
}
+static void checkSlot(etInt16 id, etMemory* mem, int slot, etUInt16 size, etUInt16 nObj) {
+ char text[32];
+ sprintf(text, "slot %d size", size);
+ EXPECT_EQUAL_UINT16(id, text, size, etMemory_FreeList_sizeObjects(mem, slot));
+ sprintf(text, "slot %d nobj", nObj);
+ EXPECT_EQUAL_UINT16(id, text, nObj, etMemory_FreeList_nObjects(mem, slot));
+}
+
+static void checkState(etInt16 id, etMemory* mem, const char* text, etUInt32 actual, etUInt32 expected) {
+ int slot;
+
+ EXPECT_EQUAL_UINT32(id, text, actual, expected);
+ EXPECT_EQUAL_UINT16(id, "free slots", NSLOTS-NSIZES, etMemory_FreeList_freeSlots(mem));
+
+ slot = 0;
+ checkSlot(id, mem, slot++, SIZE5, NOBJ);
+ checkSlot(id, mem, slot++, SIZE0, NOBJ);
+ checkSlot(id, mem, slot++, SIZE4, NOBJ);
+ checkSlot(id, mem, slot++, SIZE1, NOBJ);
+ slot++;
+ checkSlot(id, mem, slot++, SIZE2, NOBJ);
+ checkSlot(id, mem, slot++, SIZE6, NOBJ);
+ checkSlot(id, mem, slot++, SIZE3, NOBJ);
+}
+
static void TestEtMemory_testFreeList(etInt16 id) {
static etUInt8 buffer[BUF_SIZE];
static etUInt8 sizes[NSIZES] = { SIZE0, SIZE1, SIZE2, SIZE3, SIZE4, SIZE5, SIZE6 };
etUInt8* objects[NSIZES][NOBJ];
etMemory* mem = etMemory_FreeList_init(buffer, BUF_SIZE, NSLOTS);
- etUInt32 free = etMemory_FreeList_freeHeapMem(mem);
+ etUInt32 free = etMemory_FreeList_getFreeHeapMem(mem);
etUInt32 diff, total;
+ int slot;
printf("initial free heap is %ld\n", free);
@@ -129,48 +181,24 @@ static void TestEtMemory_testFreeList(etInt16 id) {
local_dump_statistics(mem, NSLOTS);
diff = free;
- free = etMemory_FreeList_freeHeapMem(mem);
+ free = etMemory_FreeList_getFreeHeapMem(mem);
diff -= free;
+ /* correction by management data */
+ diff -= NSIZES*NOBJ*etMemory_FreeList_MgmtDataPerObject();
+
printf("free heap is %ld\n", free);
- EXPECT_EQUAL_UINT32(id, "allocated total", total, diff);
- EXPECT_EQUAL_UINT16(id, "free slots", NSLOTS-NSIZES, etMemory_FreeList_freeSlots(mem));
+ fflush(stdout);
- EXPECT_EQUAL_UINT16(id, "slot 0 size", SIZE0, etMemory_FreeList_sizeObjects(mem, 0));
- EXPECT_EQUAL_UINT16(id, "slot 0 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 0));
- EXPECT_EQUAL_UINT16(id, "slot 2 size", SIZE4, etMemory_FreeList_sizeObjects(mem, 1));
- EXPECT_EQUAL_UINT16(id, "slot 2 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 1));
- EXPECT_EQUAL_UINT16(id, "slot 4 size", SIZE1, etMemory_FreeList_sizeObjects(mem, 2));
- EXPECT_EQUAL_UINT16(id, "slot 4 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 2));
- EXPECT_EQUAL_UINT16(id, "slot 1 size", SIZE2, etMemory_FreeList_sizeObjects(mem, 4));
- EXPECT_EQUAL_UINT16(id, "slot 1 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 4));
- EXPECT_EQUAL_UINT16(id, "slot 3 size", SIZE6, etMemory_FreeList_sizeObjects(mem, 5));
- EXPECT_EQUAL_UINT16(id, "slot 3 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 5));
- EXPECT_EQUAL_UINT16(id, "slot 5 size", SIZE3, etMemory_FreeList_sizeObjects(mem, 6));
- EXPECT_EQUAL_UINT16(id, "slot 5 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 6));
- EXPECT_EQUAL_UINT16(id, "slot 6 size", SIZE5, etMemory_FreeList_sizeObjects(mem, 7));
- EXPECT_EQUAL_UINT16(id, "slot 6 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 7));
+ /* do checks */
+ checkState(id, mem, "allocated total", total, diff);
+ /* allocate and free again */
local_alloc(id, mem, objects, sizes);
local_free(id, mem, objects, sizes);
- EXPECT_EQUAL_UINT32(id, "free unchanged", free, etMemory_FreeList_freeHeapMem(mem));
- EXPECT_EQUAL_UINT16(id, "free slots", NSLOTS-NSIZES, etMemory_FreeList_freeSlots(mem));
-
- EXPECT_EQUAL_UINT16(id, "slot 0 size", SIZE0, etMemory_FreeList_sizeObjects(mem, 0));
- EXPECT_EQUAL_UINT16(id, "slot 0 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 0));
- EXPECT_EQUAL_UINT16(id, "slot 2 size", SIZE4, etMemory_FreeList_sizeObjects(mem, 1));
- EXPECT_EQUAL_UINT16(id, "slot 2 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 1));
- EXPECT_EQUAL_UINT16(id, "slot 4 size", SIZE1, etMemory_FreeList_sizeObjects(mem, 2));
- EXPECT_EQUAL_UINT16(id, "slot 4 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 2));
- EXPECT_EQUAL_UINT16(id, "slot 1 size", SIZE2, etMemory_FreeList_sizeObjects(mem, 4));
- EXPECT_EQUAL_UINT16(id, "slot 1 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 4));
- EXPECT_EQUAL_UINT16(id, "slot 3 size", SIZE6, etMemory_FreeList_sizeObjects(mem, 5));
- EXPECT_EQUAL_UINT16(id, "slot 3 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 5));
- EXPECT_EQUAL_UINT16(id, "slot 5 size", SIZE3, etMemory_FreeList_sizeObjects(mem, 6));
- EXPECT_EQUAL_UINT16(id, "slot 5 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 6));
- EXPECT_EQUAL_UINT16(id, "slot 6 size", SIZE5, etMemory_FreeList_sizeObjects(mem, 7));
- EXPECT_EQUAL_UINT16(id, "slot 6 nobj", NOBJ, etMemory_FreeList_nObjects(mem, 7));
+ /* expect same results as before */
+ checkState(id, mem, "free unchanged", free, etMemory_FreeList_getFreeHeapMem(mem));
}
static void TestEtMemory_testFreeListOverflow(etInt16 id) {
@@ -186,6 +214,7 @@ static void TestEtMemory_testFreeListOverflow(etInt16 id) {
void TestEtMemory_runSuite(void){
etUnit_openTestSuite("org.eclipse.etrice.runtime.c.tests.TestMemory");
+ ADD_TESTCASE(TestEtMemory_testVariableSize);
ADD_TESTCASE(TestEtMemory_testFixedSize);
ADD_TESTCASE(TestEtMemory_testFreeList);
ADD_TESTCASE(TestEtMemory_testFreeListOverflow);

Back to the top