1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkThread_DEFINED
9#define SkThread_DEFINED
10
11#include "SkTypes.h"
12
13// SK_ATOMICS_PLATFORM_H must provide inline implementations for the following declarations.
14
15/** Atomically adds one to the int referenced by addr and returns the previous value.
16 *  No additional memory barrier is required; this must act as a compiler barrier.
17 */
18static int32_t sk_atomic_inc(int32_t* addr);
19static int64_t sk_atomic_inc(int64_t* addr);
20
21/** Atomically adds inc to the int referenced by addr and returns the previous value.
22 *  No additional memory barrier is required; this must act as a compiler barrier.
23 */
24static int32_t sk_atomic_add(int32_t* addr, int32_t inc);
25
26/** Atomically subtracts one from the int referenced by addr and returns the previous value.
27 *  This must act as a release (SL/S) memory barrier and as a compiler barrier.
28 */
29static int32_t sk_atomic_dec(int32_t* addr);
30
31/** Atomic compare and set.
32 *  If *addr == before, set *addr to after and return true, otherwise return false.
33 *  This must act as a release (SL/S) memory barrier and as a compiler barrier.
34 */
35static bool sk_atomic_cas(int32_t* addr, int32_t before, int32_t after);
36
37/** If sk_atomic_dec does not act as an acquire (L/SL) barrier,
38 *  this must act as an acquire (L/SL) memory barrier and as a compiler barrier.
39 */
40static void sk_membar_acquire__after_atomic_dec();
41
42/** If sk_atomic_conditional_inc does not act as an acquire (L/SL) barrier,
43 *  this must act as an acquire (L/SL) memory barrier and as a compiler barrier.
44 */
45static void sk_membar_acquire__after_atomic_conditional_inc();
46
47#include SK_ATOMICS_PLATFORM_H
48
49/** Atomically adds one to the int referenced by addr iff the referenced int was not 0
50 *  and returns the previous value.
51 *  No additional memory barrier is required; this must act as a compiler barrier.
52 */
53template<typename INT_TYPE> static inline INT_TYPE sk_atomic_conditional_inc(INT_TYPE* addr) {
54    INT_TYPE prev;
55    do {
56        prev = *addr;
57        if (0 == prev) {
58            break;
59        }
60    } while (!sk_atomic_cas(addr, prev, prev+1));
61    return prev;
62}
63
64// SK_BARRIERS_PLATFORM_H must provide implementations for the following declarations:
65
66/** Prevent the compiler from reordering across this barrier. */
67static void sk_compiler_barrier();
68
69/** Read T*, with at least an acquire barrier.
70 *
71 *  Only needs to be implemented for T which can be atomically read.
72 */
73template <typename T> T sk_acquire_load(T*);
74
75/** Write T*, with at least a release barrier.
76 *
77 *  Only needs to be implemented for T which can be atomically written.
78 */
79template <typename T> void sk_release_store(T*, T);
80
81#include SK_BARRIERS_PLATFORM_H
82
83/** SK_MUTEX_PLATFORM_H must provide the following (or equivalent) declarations.
84
85class SkBaseMutex {
86public:
87    void acquire();     // Block until this thread owns the mutex.
88    void release();     // Assuming this thread owns the mutex, release it.
89    void assertHeld();  // If SK_DEBUG, assert this thread owns the mutex.
90};
91
92class SkMutex : SkBaseMutex {
93public:
94    SkMutex();
95    ~SkMutex();
96};
97
98#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = ...
99*/
100
101#include SK_MUTEX_PLATFORM_H
102
103
104class SkAutoMutexAcquire : SkNoncopyable {
105public:
106    explicit SkAutoMutexAcquire(SkBaseMutex& mutex) : fMutex(&mutex) {
107        SkASSERT(fMutex != NULL);
108        mutex.acquire();
109    }
110
111    explicit SkAutoMutexAcquire(SkBaseMutex* mutex) : fMutex(mutex) {
112        if (mutex) {
113            mutex->acquire();
114        }
115    }
116
117    /** If the mutex has not been released, release it now. */
118    ~SkAutoMutexAcquire() {
119        if (fMutex) {
120            fMutex->release();
121        }
122    }
123
124    /** If the mutex has not been released, release it now. */
125    void release() {
126        if (fMutex) {
127            fMutex->release();
128            fMutex = NULL;
129        }
130    }
131
132    /** Assert that we're holding the mutex. */
133    void assertHeld() {
134        SkASSERT(fMutex);
135        fMutex->assertHeld();
136    }
137
138private:
139    SkBaseMutex* fMutex;
140};
141#define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire)
142
143#endif
144