1/*
2 * Copyright 2015 Google Inc.
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 SkMutex_DEFINED
9#define SkMutex_DEFINED
10
11#include "../private/SkSemaphore.h"
12#include "../private/SkThreadID.h"
13#include "SkTypes.h"
14
15#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name;
16
17class SkBaseMutex {
18public:
19    constexpr SkBaseMutex() = default;
20
21    void acquire() {
22        fSemaphore.wait();
23        SkDEBUGCODE(fOwner = SkGetThreadID();)
24    }
25
26    void release() {
27        this->assertHeld();
28        SkDEBUGCODE(fOwner = kIllegalThreadID;)
29        fSemaphore.signal();
30    }
31
32    void assertHeld() {
33        SkASSERT(fOwner == SkGetThreadID());
34    }
35
36protected:
37    SkBaseSemaphore fSemaphore{1};
38    SkDEBUGCODE(SkThreadID fOwner{kIllegalThreadID};)
39};
40
41class SkMutex : public SkBaseMutex {
42public:
43    using SkBaseMutex::SkBaseMutex;
44    ~SkMutex() { fSemaphore.cleanup(); }
45};
46
47class SkAutoMutexAcquire {
48public:
49    template <typename T>
50    SkAutoMutexAcquire(T* mutex) : fMutex(mutex) {
51        if (mutex) {
52            mutex->acquire();
53        }
54        fRelease = [](void* mutex) { ((T*)mutex)->release(); };
55    }
56
57    template <typename T>
58    SkAutoMutexAcquire(T& mutex) : SkAutoMutexAcquire(&mutex) {}
59
60    ~SkAutoMutexAcquire() { this->release(); }
61
62    void release() {
63        if (fMutex) {
64            fRelease(fMutex);
65        }
66        fMutex = nullptr;
67    }
68
69private:
70    void*  fMutex;
71    void (*fRelease)(void*);
72};
73#define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire)
74
75// SkAutoExclusive is a lighter weight version of SkAutoMutexAcquire.
76// It assumes that there is a valid mutex, obviating the null check.
77class SkAutoExclusive {
78public:
79    template <typename T>
80    SkAutoExclusive(T& mutex) : fMutex(&mutex) {
81        mutex.acquire();
82
83        fRelease = [](void* mutex) { ((T*)mutex)->release(); };
84    }
85    ~SkAutoExclusive() { fRelease(fMutex); }
86
87private:
88    void* fMutex;
89    void (*fRelease)(void*);
90};
91#define SkAutoExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoExclusive)
92
93#endif//SkMutex_DEFINED
94