Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2021-03-07 16:08:49 +0300
committerDavid Crocker <dcrocker@eschertech.com>2021-03-07 16:08:49 +0300
commitb4f04a76ef0dc8a6ac7a1ec1f34dd5d5b8d91ebf (patch)
tree8e565bb9aff4c5a93a7560dd419aa68c2081ed47 /src/Platform
parentb26b9cd7e3506fa243031975578e26a42ab0c2fc (diff)
Fixes to StringHandle and string expressions
Diffstat (limited to 'src/Platform')
-rw-r--r--src/Platform/Heap.cpp112
-rw-r--r--src/Platform/Heap.h22
2 files changed, 98 insertions, 36 deletions
diff --git a/src/Platform/Heap.cpp b/src/Platform/Heap.cpp
index 74a02783..b38bada4 100644
--- a/src/Platform/Heap.cpp
+++ b/src/Platform/Heap.cpp
@@ -14,6 +14,7 @@
#include <Platform/Platform.h>
#include <Platform/RepRap.h>
#include <General/String.h>
+#include <atomic>
#define CHECK_HANDLES (1) // set nonzero to check that handles are valid before dereferencing them
@@ -29,6 +30,9 @@ struct StorageSpace
struct IndexSlot
{
StorageSpace *storage;
+ std::atomic<unsigned int> refCount;
+
+ IndexSlot() noexcept : storage(nullptr), refCount(0) { }
};
struct IndexBlock
@@ -38,6 +42,8 @@ struct IndexBlock
void operator delete(void* ptr) noexcept {}
void operator delete(void* ptr, std::align_val_t align) noexcept {}
+ IndexBlock() noexcept : next(nullptr) { }
+
IndexBlock *next;
IndexSlot slots[IndexBlockSlots];
};
@@ -58,7 +64,7 @@ struct HeapBlock
ReadWriteLock StringHandle::heapLock;
IndexBlock *StringHandle::indexRoot = nullptr;
HeapBlock *StringHandle::heapRoot = nullptr;
-size_t StringHandle::spaceToRecycle = 0;
+std::atomic<size_t> StringHandle::spaceToRecycle = 0;
size_t StringHandle::totalIndexSpace = 0;
size_t StringHandle::totalHeapSpace = 0;
unsigned int StringHandle::gcCyclesDone = 0;
@@ -150,7 +156,7 @@ unsigned int StringHandle::gcCyclesDone = 0;
for (size_t i = 0; i < IndexBlockSlots; ++i)
{
char * const p = (char *)indexBlock->slots[i].storage;
- if (p >= startAddr && p < endAddr)
+ if (p != nullptr && p >= startAddr && p < endAddr)
{
indexBlock->slots[i].storage = reinterpret_cast<StorageSpace*>(p - moveDown);
--numHandles;
@@ -179,7 +185,7 @@ unsigned int StringHandle::gcCyclesDone = 0;
++numHeapErrors;
break;
}
- p += reinterpret_cast<const StorageSpace*>(p)->length & (~1u);
+ p += (reinterpret_cast<const StorageSpace*>(p)->length & (~1u)) + sizeof(StorageSpace::length);
}
}
@@ -202,20 +208,21 @@ unsigned int StringHandle::gcCyclesDone = 0;
for (HeapBlock *currentBlock = heapRoot; currentBlock != nullptr; currentBlock = currentBlock->next)
{
const char *p = currentBlock->data;
- if (st >= currentBlock->data && st < currentBlock->data + currentBlock->allocated)
+ const char * const limit = currentBlock->data + currentBlock->allocated;
+ if (st >= p && st < limit)
{
- while (p < currentBlock->data + currentBlock->allocated)
+ while (p < limit)
{
if (p == st)
{
found = true;
- if (reinterpret_cast<const StorageSpace*>(p)->length & 1)
+ if (reinterpret_cast<const StorageSpace*>(p)->length & 1u)
{
++numHandleFreeErrors;
}
break;
}
- p += reinterpret_cast<const StorageSpace*>(p)->length & (~1u);
+ p += (reinterpret_cast<const StorageSpace*>(p)->length & (~1u)) + sizeof(StorageSpace::length);
}
break;
}
@@ -254,6 +261,7 @@ unsigned int StringHandle::gcCyclesDone = 0;
{
if (curBlock->slots[i].storage == nullptr)
{
+ curBlock->slots[i].refCount = 0;
return &curBlock->slots[i];
}
}
@@ -264,10 +272,6 @@ unsigned int StringHandle::gcCyclesDone = 0;
// If we get here then we didn't find a free handle entry
IndexBlock * const newIndexBlock = new IndexBlock;
totalIndexSpace += sizeof(IndexBlock);
- for (size_t i = 0; i < IndexBlockSlots; ++i)
- {
- newIndexBlock->slots[i].storage = nullptr;
- }
if (prevIndexBlock == nullptr)
{
@@ -282,13 +286,13 @@ unsigned int StringHandle::gcCyclesDone = 0;
}
// Allocate the requested space. If 'length' is above the maximum supported size, it will be truncated.
-/*static*/ StorageSpace *StringHandle::AllocateSpace(uint16_t length) noexcept
+/*static*/ StorageSpace *StringHandle::AllocateSpace(size_t length) noexcept
{
#if CHECK_HANDLES
RRF_ASSERT(heapLock.GetWriteLockOwner() == TaskBase::GetCallerTaskHandle());
#endif
- length = min<size_t>(((size_t)length + 1) & (~1u), HeapBlockSize - sizeof(StorageSpace::length)); // round to an even length to keep things aligned and limit to max size
+ length = min<size_t>((length + 1) & (~1u), HeapBlockSize - sizeof(StorageSpace::length)); // round to an even length to keep things aligned and limit to max size
bool collected = false;
do
@@ -305,7 +309,7 @@ unsigned int StringHandle::gcCyclesDone = 0;
}
// There is no space in any existing heap block. Decide whether to garbage collect and try again, or allocate a new block.
- if (collected || spaceToRecycle < length * 8)
+ if (collected || spaceToRecycle < length * 4)
{
break;
}
@@ -333,27 +337,31 @@ unsigned int StringHandle::gcCyclesDone = 0;
// StringHandle members
// Build a handle from a single null-terminated string
-StringHandle::StringHandle(const char *s) noexcept
-{
- WriteLocker locker(heapLock); // prevent other tasks modifying the heap
- InternalAssign(s, strlen(s));
-}
+StringHandle::StringHandle(const char *s) noexcept : StringHandle(s, strlen(s)) { }
// Build a handle from a character array and a length
StringHandle::StringHandle(const char *s, size_t len) noexcept
{
- WriteLocker locker(heapLock); // prevent other tasks modifying the heap
- InternalAssign(s, len);
+ if (len == 0)
+ {
+ slotPtr = nullptr;
+ }
+ else
+ {
+ WriteLocker locker(heapLock); // prevent other tasks modifying the heap
+ InternalAssign(s, len);
+ }
}
void StringHandle::Assign(const char *s) noexcept
{
- WriteLocker locker(heapLock); // prevent other tasks modifying the heap
- if (slotPtr != nullptr)
+ Delete();
+ const size_t len = strlen(s);
+ if (len != 0)
{
- InternalDelete();
+ WriteLocker locker(heapLock); // prevent other tasks modifying the heap
+ InternalAssign(s, len);
}
- InternalAssign(s, strlen(s));
}
void StringHandle::InternalAssign(const char *s, size_t len) noexcept
@@ -364,6 +372,7 @@ void StringHandle::InternalAssign(const char *s, size_t len) noexcept
memcpy(space->data, s, lengthToCopy);
space->data[lengthToCopy] = 0;
slot->storage = space;
+ slot->refCount = 1;
slotPtr = slot;
}
@@ -371,16 +380,29 @@ void StringHandle::Delete() noexcept
{
if (slotPtr != nullptr)
{
- WriteLocker locker(heapLock); // prevent other tasks modifying the heap
+ ReadLocker locker(heapLock); // prevent other tasks modifying the heap
InternalDelete();
}
}
+void StringHandle::IncreaseRefCount() noexcept
+{
+ if (slotPtr != nullptr)
+ {
+ ++slotPtr->refCount;
+ }
+}
+
+// Caller must have at least a read lock when calling this
void StringHandle::InternalDelete() noexcept
{
- ReleaseSpace(slotPtr->storage); // release the space
- slotPtr->storage = nullptr; // release the handle entry
- slotPtr = nullptr; // clear the pointer to the handle entry
+ RRF_ASSERT(slotPtr->refCount != 0);
+ if (--slotPtr->refCount == 0)
+ {
+ ReleaseSpace(slotPtr->storage); // release the space
+ slotPtr->storage = nullptr; // release the handle entry
+ }
+ slotPtr = nullptr; // clear the pointer to the handle entry
}
ReadLockedPointer<const char> StringHandle::Get() const noexcept
@@ -393,8 +415,8 @@ ReadLockedPointer<const char> StringHandle::Get() const noexcept
ReadLocker locker(heapLock);
#if CHECK_HANDLES
+ // Check that the handle points into an index block
RRF_ASSERT(((uint32_t)slotPtr & 3) == 0);
- // Check that the handle points into an index block and is not null
bool ok = false;
for (IndexBlock *indexBlock = indexRoot; indexBlock != nullptr; indexBlock = indexBlock->next)
{
@@ -405,6 +427,7 @@ ReadLockedPointer<const char> StringHandle::Get() const noexcept
}
}
RRF_ASSERT(ok);
+ RRF_ASSERT(slotPtr->refCount != 0);
#endif
return ReadLockedPointer<const char>(locker, slotPtr->storage->data);
@@ -417,12 +440,11 @@ size_t StringHandle::GetLength() const noexcept
return 0;
}
-
ReadLocker locker(heapLock);
#if CHECK_HANDLES
- RRF_ASSERT(((uint32_t)slotPtr & 3) == 0);
// Check that the handle points into an index block and is not null
+ RRF_ASSERT(((uint32_t)slotPtr & 3) == 0);
bool ok = false;
for (IndexBlock *indexBlock = indexRoot; indexBlock != nullptr; indexBlock = indexBlock->next)
{
@@ -433,6 +455,7 @@ size_t StringHandle::GetLength() const noexcept
}
}
RRF_ASSERT(ok);
+ RRF_ASSERT(slotPtr->refCount != 0);
#endif
return strlen(slotPtr->storage->data);
@@ -446,8 +469,31 @@ size_t StringHandle::GetLength() const noexcept
{
temp.copy("Heap OK");
}
- temp.catf(", index memory %u, heap memory %u, reclaimable space %u, gc cycles %u\n", totalIndexSpace, totalHeapSpace, spaceToRecycle, gcCyclesDone);
+ temp.catf(", index memory %u, heap memory %u, reclaimable space %u, gc cycles %u\n", totalIndexSpace, totalHeapSpace, (unsigned int)spaceToRecycle, gcCyclesDone);
reprap.GetPlatform().Message(mt, temp.c_str());
}
+// AutoStringHandle members
+
+AutoStringHandle::AutoStringHandle(const AutoStringHandle& other) noexcept
+{
+ IncreaseRefCount();
+}
+
+AutoStringHandle& AutoStringHandle::operator=(const AutoStringHandle& other) noexcept
+{
+ if (slotPtr != other.slotPtr)
+ {
+ Delete();
+ slotPtr = other.slotPtr;
+ IncreaseRefCount();
+ }
+ return *this;
+}
+
+AutoStringHandle::~AutoStringHandle()
+{
+ StringHandle::Delete();
+}
+
// End
diff --git a/src/Platform/Heap.h b/src/Platform/Heap.h
index 430df1ac..fc465d94 100644
--- a/src/Platform/Heap.h
+++ b/src/Platform/Heap.h
@@ -17,6 +17,9 @@ class StorageSpace;
class HeapBlock;
class IndexBlock;
+// Note: StringHandle is a union member in ExpressionValue, therefore it cannot have a non-trivial destructor, copy constructor etc.
+// This means that when an object containing a StringHandle is copied or destroyed, that object must handle the reference count.
+// Classes other than ExpressionValue should use AutoStringHandle instead;
class StringHandle
{
public:
@@ -27,6 +30,7 @@ public:
ReadLockedPointer<const char> Get() const noexcept;
size_t GetLength() const noexcept;
void Delete() noexcept;
+ void IncreaseRefCount() noexcept;
bool IsNull() const noexcept { return slotPtr == nullptr; }
void Assign(const char *s) noexcept;
@@ -37,12 +41,12 @@ public:
static bool CheckIntegrity(const StringRef& errmsg) noexcept;
static void Diagnostics(MessageType mt) noexcept;
-private:
+protected:
void InternalAssign(const char *s, size_t len) noexcept;
void InternalDelete() noexcept;
static IndexSlot *AllocateHandle() noexcept;
- static StorageSpace *AllocateSpace(uint16_t length) noexcept;
+ static StorageSpace *AllocateSpace(size_t length) noexcept;
static void ReleaseSpace(StorageSpace *ptr) noexcept;
static void GarbageCollectInternal() noexcept;
static void AdjustHandles(char *startAddr, char *endAddr, size_t moveDown, unsigned int numHandles) noexcept;
@@ -52,10 +56,22 @@ private:
static ReadWriteLock heapLock;
static IndexBlock *indexRoot;
static HeapBlock *heapRoot;
- static size_t spaceToRecycle;
+ static std::atomic<size_t> spaceToRecycle;
static size_t totalIndexSpace;
static size_t totalHeapSpace;
static unsigned int gcCyclesDone;
};
+// Version of StringHandle that updates the reference counts automatically
+class AutoStringHandle : public StringHandle
+{
+public:
+ AutoStringHandle() noexcept : StringHandle() { }
+ AutoStringHandle(const char *s) noexcept : StringHandle(s) { }
+ AutoStringHandle(const char *s, size_t len) noexcept : StringHandle(s, len) { }
+ AutoStringHandle(const AutoStringHandle& other) noexcept;
+ AutoStringHandle& operator=(const AutoStringHandle& other) noexcept;
+ ~AutoStringHandle();
+};
+
#endif /* SRC_PLATFORM_HEAP_H_ */