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);
19
20/** Atomically adds inc to the int referenced by addr and returns the previous value.
21 *  No additional memory barrier is required; this must act as a compiler barrier.
22 */
23static int32_t sk_atomic_add(int32_t* addr, int32_t inc);
24
25/** Atomically subtracts one from the int referenced by addr and returns the previous value.
26 *  This must act as a release (SL/S) memory barrier and as a compiler barrier.
27 */
28static int32_t sk_atomic_dec(int32_t* addr);
29
30/** Atomic compare and set.
31 *  If *addr == before, set *addr to after and return true, otherwise return false.
32 *  This must act as a release (SL/S) memory barrier and as a compiler barrier.
33 */
34static bool sk_atomic_cas(int32_t* addr, int32_t before, int32_t after);
35
36/** If sk_atomic_dec does not act as an acquire (L/SL) barrier,
37 *  this must act as an acquire (L/SL) memory barrier and as a compiler barrier.
38 */
39static void sk_membar_acquire__after_atomic_dec();
40
41/** If sk_atomic_conditional_inc does not act as an acquire (L/SL) barrier,
42 *  this must act as an acquire (L/SL) memory barrier and as a compiler barrier.
43 */
44static void sk_membar_acquire__after_atomic_conditional_inc();
45
46#include SK_ATOMICS_PLATFORM_H
47
48/** Atomically adds one to the int referenced by addr iff the referenced int was not 0
49 *  and returns the previous value.
50 *  No additional memory barrier is required; this must act as a compiler barrier.
51 */
52static inline int32_t sk_atomic_conditional_inc(int32_t* addr) {
53    int32_t prev;
54    do {
55        prev = *addr;
56        if (0 == prev) {
57            break;
58        }
59    } while (!sk_atomic_cas(addr, prev, prev+1));
60    return prev;
61}
62
63// SK_BARRIERS_PLATFORM_H must provide implementations for the following declarations:
64
65/** Prevent the compiler from reordering across this barrier. */
66static void sk_compiler_barrier();
67
68/** Read T*, with at least an acquire barrier.
69 *
70 *  Only needs to be implemented for T which can be atomically read.
71 */
72template <typename T> T sk_acquire_load(T*);
73
74/** Write T*, with at least a release barrier.
75 *
76 *  Only needs to be implemented for T which can be atomically written.
77 */
78template <typename T> void sk_release_store(T*, T);
79
80#include SK_BARRIERS_PLATFORM_H
81
82/** SK_MUTEX_PLATFORM_H must provide the following (or equivalent) declarations.
83
84class SkBaseMutex {
85public:
86    void acquire();     // Block until this thread owns the mutex.
87    void release();     // Assuming this thread owns the mutex, release it.
88    void assertHeld();  // If SK_DEBUG, assert this thread owns the mutex.
89};
90
91class SkMutex : SkBaseMutex {
92public:
93    SkMutex();
94    ~SkMutex();
95};
96
97#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = ...
98#define SK_DECLARE_GLOBAL_MUTEX(name) 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