180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2011 Google Inc.
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThread.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <pthread.h>
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <errno.h>
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifndef SK_BUILD_FOR_ANDROID
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/**
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru We prefer the GCC intrinsic implementation of the atomic operations over the
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMutex-based implementation. The SkMutex version suffers from static
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru destructor ordering problems.
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru Note clang also defines the GCC version macros and implements the intrinsics.
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TODO: Verify that gcc-style __sync_* intrinsics work on ARM
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru According to this the intrinsics are supported on ARM in LLVM 2.7+
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru http://llvm.org/releases/2.7/docs/ReleaseNotes.html
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru*/
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    #if (defined(__x86_64) || defined(__i386__))
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        #define GCC_INTRINSIC
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    #endif
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(GCC_INTRINSIC)
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_inc(int32_t* addr)
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return __sync_fetch_and_add(addr, 1);
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_add(int32_t* addr, int32_t inc)
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return __sync_fetch_and_add(addr, inc);
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_dec(int32_t* addr)
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return __sync_fetch_and_add(addr, -1);
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_dec() { }
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_conditional_inc(int32_t* addr)
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int32_t value = *addr;
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (true) {
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (value == 0) {
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return 0;
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int32_t before = __sync_val_compare_and_swap(addr, value, value + 1);
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (before == value) {
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return value;
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            value = before;
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_conditional_inc() { }
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex gAtomicMutex;
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_inc(int32_t* addr)
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoMutexAcquire ac(gAtomicMutex);
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int32_t value = *addr;
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *addr = value + 1;
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return value;
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_add(int32_t* addr, int32_t inc)
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoMutexAcquire ac(gAtomicMutex);
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int32_t value = *addr;
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *addr = value + inc;
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return value;
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_dec(int32_t* addr)
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoMutexAcquire ac(gAtomicMutex);
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int32_t value = *addr;
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *addr = value - 1;
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return value;
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_dec() { }
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_conditional_inc(int32_t* addr)
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoMutexAcquire ac(gAtomicMutex);
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int32_t value = *addr;
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (value != 0) ++*addr;
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return value;
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_conditional_inc() { }
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif // SK_BUILD_FOR_ANDROID
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//////////////////////////////////////////////////////////////////////////////
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void print_pthread_error(int status) {
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    switch (status) {
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case 0: // success
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case EINVAL:
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDebugf("pthread error [%d] EINVAL\n", status);
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case EBUSY:
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDebugf("pthread error [%d] EBUSY\n", status);
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    default:
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDebugf("pthread error [%d] unknown\n", status);
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef SK_USE_POSIX_THREADS
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::SkMutex() {
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status;
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    status = pthread_mutex_init(&fMutex, NULL);
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (status != 0) {
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        print_pthread_error(status);
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(0 == status);
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::~SkMutex() {
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status = pthread_mutex_destroy(&fMutex);
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // only report errors on non-global mutexes
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (status != 0) {
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        print_pthread_error(status);
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(0 == status);
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else // !SK_USE_POSIX_THREADS
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::SkMutex() {
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDEBUGFAIL("mutex storage is too small");
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status;
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutexattr_t attr;
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    status = pthread_mutexattr_init(&attr);
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    print_pthread_error(status);
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(0 == status);
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    print_pthread_error(status);
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(0 == status);
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::~SkMutex() {
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if 0
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // only report errors on non-global mutexes
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!fIsGlobal) {
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        print_pthread_error(status);
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(0 == status);
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMutex::acquire() {
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    print_pthread_error(status);
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(0 == status);
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMutex::release() {
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    print_pthread_error(status);
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(0 == status);
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif // !SK_USE_POSIX_THREADS
198