aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/SkMemory_stdlib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkMemory_stdlib.cpp')
-rw-r--r--src/core/SkMemory_stdlib.cpp287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/core/SkMemory_stdlib.cpp b/src/core/SkMemory_stdlib.cpp
new file mode 100644
index 0000000..f1ac36b
--- /dev/null
+++ b/src/core/SkMemory_stdlib.cpp
@@ -0,0 +1,287 @@
+/* libs/corecg/SkMemory_stdlib.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "SkTypes.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef SK_DEBUG
+ #define SK_TAG_BLOCKS
+ // #define SK_TRACK_ALLOC // enable to see a printf for every alloc/free
+ // #define SK_CHECK_TAGS // enable to double-check debugging link list
+#endif
+
+#ifdef SK_TAG_BLOCKS
+
+#include "SkThread.h"
+
+// size this (as a multiple of 4) so that the total offset to the internal data
+// is at least a multiple of 8 (since some clients of our malloc may require
+// that.
+static const char kBlockHeaderTag[] = { 's', 'k', 'i', 'a', '1', '2', '3', '4' };
+static const char kBlockTrailerTag[] = { 'a', 'i', 'k', 's' };
+#define kByteFill 0xCD
+#define kDeleteFill 0xEF
+
+static SkMutex& get_block_mutex() {
+ static SkMutex* gBlockMutex;
+ if (NULL == gBlockMutex) {
+ gBlockMutex = new SkMutex;
+ }
+ return *gBlockMutex;
+}
+
+static struct SkBlockHeader* gHeader;
+
+struct SkBlockHeader {
+ SkBlockHeader* fNext;
+#ifdef SK_CHECK_TAGS
+ SkBlockHeader** fTop; // set to verify in debugger that block was alloc'd / freed with same gHeader
+ SkBlockHeader* fPrevious; // set to see in debugger previous block when corruption happens
+#endif
+ size_t fSize;
+ char fHeader[sizeof(kBlockHeaderTag)];
+ // data goes here. The offset to this point must be a multiple of 8
+ char fTrailer[sizeof(kBlockTrailerTag)];
+
+ void* add(size_t realSize)
+ {
+ SkAutoMutexAcquire ac(get_block_mutex());
+ InMutexValidate();
+ fNext = gHeader;
+#ifdef SK_CHECK_TAGS
+ fTop = &gHeader;
+ fPrevious = NULL;
+ if (fNext != NULL)
+ fNext->fPrevious = this;
+#endif
+ gHeader = this;
+ fSize = realSize;
+ memcpy(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag));
+ void* result = fTrailer;
+ void* trailer = (char*)result + realSize;
+ memcpy(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag));
+ return result;
+ }
+
+ static void Dump()
+ {
+ SkAutoMutexAcquire ac(get_block_mutex());
+ InMutexValidate();
+ SkBlockHeader* header = gHeader;
+ int count = 0;
+ size_t size = 0;
+ while (header != NULL) {
+ char scratch[256];
+ char* pos = scratch;
+ size_t size = header->fSize;
+ int* data = (int*)(void*)header->fTrailer;
+ pos += sprintf(pos, "%p 0x%08zx (%7zd) ",
+ data, size, size);
+ size >>= 2;
+ size_t ints = size > 4 ? 4 : size;
+ size_t index;
+ for (index = 0; index < ints; index++)
+ pos += sprintf(pos, "0x%08x ", data[index]);
+ pos += sprintf(pos, " (");
+ for (index = 0; index < ints; index++)
+ pos += sprintf(pos, "%g ", data[index] / 65536.0f);
+ if (ints > 0)
+ --pos;
+ pos += sprintf(pos, ") \"");
+ size_t chars = size > 16 ? 16 : size;
+ char* chPtr = (char*) data;
+ for (index = 0; index < chars; index++) {
+ char ch = chPtr[index];
+ pos += sprintf(pos, "%c", ch >= ' ' && ch < 0x7f ? ch : '?');
+ }
+ pos += sprintf(pos, "\"");
+ SkDebugf("%s\n", scratch);
+ count++;
+ size += header->fSize;
+ header = header->fNext;
+ }
+ SkDebugf("--- count %d size 0x%08x (%zd) ---\n", count, size, size);
+ }
+
+ void remove() const
+ {
+ SkAutoMutexAcquire ac(get_block_mutex());
+ SkBlockHeader** findPtr = &gHeader;
+ do {
+ SkBlockHeader* find = *findPtr;
+ SkASSERT(find != NULL);
+ if (find == this) {
+ *findPtr = fNext;
+ break;
+ }
+ findPtr = &find->fNext;
+ } while (true);
+ InMutexValidate();
+ SkASSERT(memcmp(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
+ const char* trailer = fTrailer + fSize;
+ SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
+ }
+
+ static void Validate()
+ {
+ SkAutoMutexAcquire ac(get_block_mutex());
+ InMutexValidate();
+ }
+
+private:
+ static void InMutexValidate()
+ {
+ SkBlockHeader* header = gHeader;
+ while (header != NULL) {
+ SkASSERT(memcmp(header->fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
+ char* trailer = header->fTrailer + header->fSize;
+ SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
+ header = header->fNext;
+ }
+ }
+};
+
+void Dump()
+{
+ SkBlockHeader::Dump();
+}
+
+void ValidateHeap()
+{
+ SkBlockHeader::Validate();
+}
+#else
+void Dump() {}
+void ValidateHeap() {}
+#endif
+
+void sk_throw()
+{
+#ifdef ANDROID
+ fprintf(stderr, "throwing...\n");
+#endif
+ SkASSERT(!"sk_throw");
+ abort();
+}
+
+void sk_out_of_memory(void)
+{
+#ifdef ANDROID
+ fprintf(stderr,"- out of memory in SGL -\n");
+#endif
+ SkASSERT(!"sk_out_of_memory");
+ abort();
+}
+
+void* sk_malloc_throw(size_t size)
+{
+ return sk_malloc_flags(size, SK_MALLOC_THROW);
+}
+
+void* sk_realloc_throw(void* addr, size_t size)
+{
+#ifdef SK_TAG_BLOCKS
+ ValidateHeap();
+ if (addr != NULL) {
+ SkBlockHeader* header = (SkBlockHeader*)
+ ((char*)addr - SK_OFFSETOF(SkBlockHeader, fTrailer));
+ header->remove();
+#ifdef SK_TRACK_ALLOC
+ printf("sk_realloc_throw %p oldSize=%zd\n", addr, header->fSize);
+#endif
+ addr = header;
+ }
+ size_t realSize = size;
+ if (size)
+ size += sizeof(SkBlockHeader);
+#endif
+
+ void* p = realloc(addr, size);
+ if (size == 0)
+ {
+ ValidateHeap();
+ return p;
+ }
+
+ if (p == NULL)
+ sk_throw();
+#ifdef SK_TAG_BLOCKS
+ else
+ {
+ SkBlockHeader* header = (SkBlockHeader*) p;
+ p = header->add(realSize);
+#ifdef SK_TRACK_ALLOC
+ printf("sk_realloc_throw %p size=%zd\n", p, realSize);
+#endif
+ }
+#endif
+ ValidateHeap();
+ return p;
+}
+
+void sk_free(void* p)
+{
+ if (p)
+ {
+ ValidateHeap();
+#ifdef SK_TAG_BLOCKS
+ SkBlockHeader* header = (SkBlockHeader*)
+ ((char*)p - SK_OFFSETOF(SkBlockHeader, fTrailer));
+ header->remove();
+#ifdef SK_TRACK_ALLOC
+ printf("sk_free %p size=%zd\n", p, header->fSize);
+#endif
+ size_t size = header->fSize + sizeof(SkBlockHeader);
+ memset(header, kDeleteFill, size);
+ p = header;
+#endif
+ ValidateHeap();
+ free(p);
+ ValidateHeap();
+ }
+}
+
+void* sk_malloc_flags(size_t size, unsigned flags)
+{
+ ValidateHeap();
+#ifdef SK_TAG_BLOCKS
+ size_t realSize = size;
+ size += sizeof(SkBlockHeader);
+#endif
+
+ void* p = malloc(size);
+ if (p == NULL)
+ {
+ if (flags & SK_MALLOC_THROW)
+ sk_throw();
+ }
+#ifdef SK_TAG_BLOCKS
+ else
+ {
+ SkBlockHeader* header = (SkBlockHeader*) p;
+ p = header->add(realSize);
+ memset(p, kByteFill, realSize);
+#ifdef SK_TRACK_ALLOC
+ printf("sk_malloc_flags %p size=%zd\n", p, realSize);
+#endif
+ }
+#endif
+ ValidateHeap();
+ return p;
+}
+