diff options
author | mtklein@google.com <mtklein@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-08 19:22:41 +0000 |
---|---|---|
committer | mtklein@google.com <mtklein@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-08 19:22:41 +0000 |
commit | 26d915cdb52034b90c2fd13eb9340df0c74e2fe2 (patch) | |
tree | 456aa8dde644e69b56728140557ee0288952075f /skia/ext | |
parent | 5c04d3a953f95665b448a6d74fee79c22ac9d375 (diff) | |
download | chromium_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.cpp | 90 |
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 } |