summaryrefslogtreecommitdiffstats
path: root/skia/ext
diff options
context:
space:
mode:
authormtklein@google.com <mtklein@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 19:22:41 +0000
committermtklein@google.com <mtklein@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 19:22:41 +0000
commit26d915cdb52034b90c2fd13eb9340df0c74e2fe2 (patch)
tree456aa8dde644e69b56728140557ee0288952075f /skia/ext
parent5c04d3a953f95665b448a6d74fee79c22ac9d375 (diff)
downloadchromium_src-26d915cdb52034b90c2fd13eb9340df0c74e2fe2.zip
chromium_src-26d915cdb52034b90c2fd13eb9340df0c74e2fe2.tar.gz
chromium_src-26d915cdb52034b90c2fd13eb9340df0c74e2fe2.tar.bz2
Add sk_calloc and sk_calloc_throw to SkMemory_new_handler.cpp.
After finding that calloc can be significantly faster than malloc+bzero on some platforms (notably, Android), Skia wants to start experimenting with using calloc where possible. For this, we've added sk_calloc and sk_calloc_throw to the SkMemory API. This CL is my ham-handed approach to add calloc support to SkMemory_new_handler.cpp. It seems to me that this exists as an alternative to SkMemory_malloc.cpp so that we can try to dodge any OOM crash that the underlying malloc implementation might helpfully provide? I've tried to mimic what I saw here for the non-throwing malloc onto sk_calloc, and just did some refactoring to make this code look a bit more like the current SkMemory_malloc.cpp. BUG=skia:1662 Review URL: https://codereview.chromium.org/23455061 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227563 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext')
-rw-r--r--skia/ext/SkMemory_new_handler.cpp90
1 files changed, 54 insertions, 36 deletions
diff --git a/skia/ext/SkMemory_new_handler.cpp b/skia/ext/SkMemory_new_handler.cpp
index dbbc494..a142f29 100644
--- a/skia/ext/SkMemory_new_handler.cpp
+++ b/skia/ext/SkMemory_new_handler.cpp
@@ -11,13 +11,21 @@
#include "third_party/skia/include/core/SkTypes.h"
#include "third_party/skia/include/core/SkThread.h"
-// This implementation of sk_malloc_flags() and friends is identical
-// to SkMemory_malloc.c, except that it disables the CRT's new_handler
-// during malloc(), when SK_MALLOC_THROW is not set (ie., when
-// sk_malloc_flags() would not abort on NULL).
+// This implementation of sk_malloc_flags() and friends is identical to
+// SkMemory_malloc.cpp, except that it disables the CRT's new_handler during
+// malloc() and calloc() when SK_MALLOC_THROW is not set (because our normal
+// new_handler itself will crash on failure when using tcmalloc).
SK_DECLARE_STATIC_MUTEX(gSkNewHandlerMutex);
+static inline void* throw_on_failure(size_t size, void* p) {
+ if (size > 0 && p == NULL) {
+ // If we've got a NULL here, the only reason we should have failed is running out of RAM.
+ sk_out_of_memory();
+ }
+ return p;
+}
+
void sk_throw() {
SkASSERT(!"sk_throw");
abort();
@@ -28,19 +36,8 @@ void sk_out_of_memory(void) {
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) {
- void* p = realloc(addr, size);
- if (size == 0) {
- return p;
- }
- if (p == NULL) {
- sk_throw();
- }
- return p;
+ return throw_on_failure(size, realloc(addr, size));
}
void sk_free(void* p) {
@@ -49,29 +46,50 @@ void sk_free(void* p) {
}
}
-void* sk_malloc_flags(size_t size, unsigned flags) {
- void* p;
+void* sk_malloc_throw(size_t size) {
+ return throw_on_failure(size, malloc(size));
+}
+
+// Platform specific ways to try really hard to get a malloc that won't crash on failure.
+static void* sk_malloc_nothrow(size_t size) {
#if defined(ANDROID)
- // Android doesn't have std::set_new_handler.
- p = malloc(size);
+ // Android doesn't have std::set_new_handler, so we just call malloc.
+ return malloc(size);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ return base::UncheckedMalloc(size);
#else
- if (!(flags & SK_MALLOC_THROW)) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- p = base::UncheckedMalloc(size);
-#else
- SkAutoMutexAcquire lock(gSkNewHandlerMutex);
- std::new_handler old_handler = std::set_new_handler(NULL);
- p = malloc(size);
- std::set_new_handler(old_handler);
-#endif
- } else {
- p = malloc(size);
- }
+ // This is not really thread safe. It only won't collide with itself, but we're totally
+ // unprotected from races with other code that calls set_new_handler.
+ SkAutoMutexAcquire lock(gSkNewHandlerMutex);
+ std::new_handler old_handler = std::set_new_handler(NULL);
+ void* p = malloc(size);
+ std::set_new_handler(old_handler);
+ return p;
#endif
- if (p == NULL) {
- if (flags & SK_MALLOC_THROW) {
- sk_throw();
- }
+}
+
+void* sk_malloc_flags(size_t size, unsigned flags) {
+ if (flags & SK_MALLOC_THROW) {
+ return sk_malloc_throw(size);
}
+ return sk_malloc_nothrow(size);
+}
+
+void* sk_calloc_throw(size_t size) {
+ return throw_on_failure(size, calloc(size, 1));
+}
+
+// Jump through the same hoops as sk_malloc_nothrow to avoid a crash, but for calloc.
+void* sk_calloc(size_t size) {
+#if defined(ANDROID)
+ return calloc(size, 1);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ return base::UncheckedCalloc(size, 1);
+#else
+ SkAutoMutexAcquire lock(gSkNewHandlerMutex);
+ std::new_handler old_handler = std::set_new_handler(NULL);
+ void* p = calloc(size, 1);
+ std::set_new_handler(old_handler);
return p;
+#endif
}