1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_PLATFORM_MUTEX_H
17#define ECMASCRIPT_PLATFORM_MUTEX_H
18
19#include <pthread.h>
20#include <atomic>
21
22#include "ecmascript/common.h"
23#ifdef DEBUG
24#define FATAL_IF_ERROR(f, rc)                           \
25    do {                                                \
26        if (rc != 0) {                                  \
27            LOG_ECMA(FATAL)<< f << " failed: " << rc;   \
28        }                                               \
29    } while (false)
30#else
31#define FATAL_IF_ERROR(f, rc) static_cast<void>(0)
32#endif
33namespace panda::ecmascript {
34
35class PUBLIC_API Mutex {
36public:
37    explicit  Mutex(bool is_init = true);
38
39    ~Mutex();
40
41    void Lock();
42
43    bool TryLock();
44
45    void Unlock();
46
47protected:
48    void Init(pthread_mutexattr_t *attrs);
49
50private:
51    pthread_mutex_t mutex_;
52    friend class ConditionVariable;
53};
54
55class RecursiveMutex : public Mutex {
56public:
57    RecursiveMutex();
58
59    ~RecursiveMutex() = default;
60
61    NO_COPY_SEMANTIC(RecursiveMutex);
62    NO_MOVE_SEMANTIC(RecursiveMutex);
63};
64
65class RWLock {
66public:
67    RWLock();
68
69    ~RWLock();
70
71    void ReadLock();
72
73    void WriteLock();
74
75    bool TryReadLock();
76
77    bool TryWriteLock();
78
79    void Unlock();
80
81private:
82    pthread_rwlock_t rwlock_;
83
84    NO_COPY_SEMANTIC(RWLock);
85    NO_MOVE_SEMANTIC(RWLock);
86};
87
88class PUBLIC_API ConditionVariable {
89public:
90    ConditionVariable();
91
92    ~ConditionVariable();
93
94    void Signal();
95
96    void SignalAll();
97
98    void Wait(Mutex *mutex);
99
100    bool TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns = 0, bool is_absolute = false);
101
102private:
103    pthread_cond_t cond_;
104};
105
106class LockHolder {
107public:
108    explicit LockHolder(Mutex &mtx) : lock_(mtx)
109    {
110        lock_.Lock();
111    }
112
113    ~LockHolder()
114    {
115        lock_.Unlock();
116    }
117
118private:
119    Mutex &lock_;
120
121    NO_COPY_SEMANTIC(LockHolder);
122    NO_MOVE_SEMANTIC(LockHolder);
123};
124
125class ReadLockHolder {
126public:
127    explicit ReadLockHolder(RWLock &lock) : lock_(lock)
128    {
129        lock_.ReadLock();
130    }
131
132    ~ReadLockHolder()
133    {
134        lock_.Unlock();
135    }
136
137private:
138    RWLock &lock_;
139
140    NO_COPY_SEMANTIC(ReadLockHolder);
141    NO_MOVE_SEMANTIC(ReadLockHolder);
142};
143
144class WriteLockHolder {
145public:
146    explicit WriteLockHolder(RWLock &lock) : lock_(lock)
147    {
148        lock_.WriteLock();
149    }
150
151    ~WriteLockHolder()
152    {
153        lock_.Unlock();
154    }
155
156private:
157    RWLock &lock_;
158
159    NO_COPY_SEMANTIC(WriteLockHolder);
160    NO_MOVE_SEMANTIC(WriteLockHolder);
161};
162}  // namespace panda::ecmascript
163#endif  // ECMASCRIPT_PLATFORM_MUTEX_H
164