1771cbf43d
This patch removes static initializers related to static and global mutexes from the final library's machine code when building on a pthread-capable system. We use PTHREAD_MUTEX_INITIALIZER to perform POD-style initialization. You need a line like the following to declare a global mutex with it: SkBaseMutex gMutex = { PTHREAD_MUTEX_INITIALIZER }; We introduce the SK_DECLARE_STATIC_MUTEX and SK_DECLARE_GLOBAL_MUTEX macros to be able to declare static/global mutexes in the source tree uniformly. SkMutex is now defined as a sub-class of SkBaseMutex, with standard construction/destruction semantics. This is useful if the mutex object is a member of another C++ class, or allocated dynamically. We also modify a few places to refer to SkBaseMutex instead of a SkMutex, where it makes sense. Generally speaking, client code should hold and use pointers to SkBaseMutex whenever they can now. We defined a new built-time macro named SK_USE_POSIX_THREADS to indicate that we're using a pthread-based SkThread.h interface. The macro will also be used in future patches to implement other helper thread synchronization classes. Finally, we inline the acquire() and release() functions in the case of Posix to improve performance a bit. Running: 'bench -repeat 10 -match mutex' on an Android device or a 2.4GHz Xeon Linux desktop shows the following improvements: Before After Galaxy Nexus 1.64 1.45 Nexus S 1.47 1.16 Xoom 1.86 1.66 Xeon 0.36 0.31 This removes 5 static mutex initializers from the library Review URL: https://codereview.appspot.com/5501066 git-svn-id: http://skia.googlecode.com/svn/trunk@3091 2bbb7eff-a529-9590-31e7-b0007b416f81
143 lines
3.9 KiB
C++
143 lines
3.9 KiB
C++
|
|
/*
|
|
* Copyright 2006 The Android Open Source Project
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
|
|
#ifndef SkThread_platform_DEFINED
|
|
#define SkThread_platform_DEFINED
|
|
|
|
#if defined(SK_BUILD_FOR_ANDROID)
|
|
|
|
#if defined(SK_BUILD_FOR_ANDROID_NDK)
|
|
|
|
#include <stdint.h>
|
|
|
|
/* Just use the GCC atomic intrinsics. They're supported by the NDK toolchain,
|
|
* have reasonable performance, and provide full memory barriers
|
|
*/
|
|
static __attribute__((always_inline)) int32_t sk_atomic_inc(int32_t *addr) {
|
|
return __sync_fetch_and_add(addr, 1);
|
|
}
|
|
|
|
static __attribute__((always_inline)) int32_t sk_atomic_dec(int32_t *addr) {
|
|
return __sync_fetch_and_add(addr, -1);
|
|
}
|
|
|
|
#else // !SK_BUILD_FOR_ANDROID_NDK
|
|
|
|
/* The platform atomics operations are slightly more efficient than the
|
|
* GCC built-ins, so use them.
|
|
*/
|
|
#include <utils/Atomic.h>
|
|
|
|
#define sk_atomic_inc(addr) android_atomic_inc(addr)
|
|
#define sk_atomic_dec(addr) android_atomic_dec(addr)
|
|
|
|
#endif // !SK_BUILD_FOR_ANDROID_NDK
|
|
|
|
#else // !SK_BUILD_FOR_ANDROID
|
|
|
|
/** Implemented by the porting layer, this function adds 1 to the int specified
|
|
by the address (in a thread-safe manner), and returns the previous value.
|
|
*/
|
|
SK_API int32_t sk_atomic_inc(int32_t* addr);
|
|
/** Implemented by the porting layer, this function subtracts 1 to the int
|
|
specified by the address (in a thread-safe manner), and returns the previous
|
|
value.
|
|
*/
|
|
SK_API int32_t sk_atomic_dec(int32_t* addr);
|
|
|
|
#endif // !SK_BUILD_FOR_ANDROID
|
|
|
|
#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
|
|
|
|
#include <utils/threads.h>
|
|
|
|
class SkMutex : android::Mutex {
|
|
public:
|
|
SkMutex() {}
|
|
~SkMutex() {}
|
|
|
|
void acquire() { this->lock(); }
|
|
void release() { this->unlock(); }
|
|
};
|
|
|
|
#else
|
|
|
|
/** Implemented by the porting layer, this function adds 1 to the int specified
|
|
by the address (in a thread-safe manner), and returns the previous value.
|
|
*/
|
|
SK_API int32_t sk_atomic_inc(int32_t* addr);
|
|
/** Implemented by the porting layer, this function subtracts 1 to the int
|
|
specified by the address (in a thread-safe manner), and returns the previous
|
|
value.
|
|
*/
|
|
SK_API int32_t sk_atomic_dec(int32_t* addr);
|
|
|
|
#endif
|
|
|
|
#ifdef SK_USE_POSIX_THREADS
|
|
|
|
#include <pthread.h>
|
|
|
|
// A SkBaseMutex is a POD structure that can be directly initialized
|
|
// at declaration time with SK_DECLARE_STATIC/GLOBAL_MUTEX. This avoids the
|
|
// generation of a static initializer in the final machine code (and
|
|
// a corresponding static finalizer).
|
|
//
|
|
struct SkBaseMutex {
|
|
void acquire() { pthread_mutex_lock(&fMutex); }
|
|
void release() { pthread_mutex_unlock(&fMutex); }
|
|
pthread_mutex_t fMutex;
|
|
};
|
|
|
|
// Using POD-style initialization prevents the generation of a static initializer
|
|
// and keeps the acquire() implementation small and fast.
|
|
#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = { PTHREAD_MUTEX_INITIALIZER }
|
|
|
|
// Special case used when the static mutex must be available globally.
|
|
#define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name = { PTHREAD_MUTEX_INITIALIZER }
|
|
|
|
// A normal mutex that requires to be initialized through normal C++ construction,
|
|
// i.e. when it's a member of another class, or allocated on the heap.
|
|
class SkMutex : public SkBaseMutex, SkNoncopyable {
|
|
public:
|
|
SkMutex();
|
|
~SkMutex();
|
|
};
|
|
|
|
#else // !SK_USE_POSIX_THREADS
|
|
|
|
// In the generic case, SkBaseMutex and SkMutex are the same thing, and we
|
|
// can't easily get rid of static initializers.
|
|
//
|
|
class SkMutex : SkNoncopyable {
|
|
public:
|
|
SkMutex();
|
|
~SkMutex();
|
|
|
|
void acquire();
|
|
void release();
|
|
|
|
private:
|
|
bool fIsGlobal;
|
|
enum {
|
|
kStorageIntCount = 64
|
|
};
|
|
uint32_t fStorage[kStorageIntCount];
|
|
};
|
|
|
|
typedef SkMutex SkBaseMutex;
|
|
|
|
#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name
|
|
#define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name
|
|
|
|
#endif // !SK_USE_POSIX_THREADS
|
|
|
|
|
|
#endif
|