17#include <condition_variable>
22#include <shared_mutex>
27#include <unordered_map>
29#include "common/lang/thread.h"
30#include "common/log/log.h"
33using std::condition_variable;
37using std::scoped_lock;
38using std::shared_mutex;
39using std::unique_lock;
43#define MUTEX_LOG LOG_DEBUG
48 static void check(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
49 static void lock(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
50 static void tryLock(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
51 static void unlock(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
53 static void toString(
string &result);
58 LockID(
const long long threadId,
const char *file,
const int line) : mFile(file), mThreadId(threadId), mLine(line)
60 LockID() : mFile(), mThreadId(0), mLine(0) {}
66 oss <<
"threaId:" << mThreadId <<
",file name:" << mFile <<
",line:" << mLine;
73 const long long mThreadId;
77 static void foundDeadLock(
LockID ¤t,
LockID &other, pthread_mutex_t *otherWaitMutex);
79 static bool deadlockCheck(
LockID ¤t, set<pthread_mutex_t *> &ownMutexs,
LockID &other,
int recusiveNum);
81 static bool deadlockCheck(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
83 static bool checkLockTimes(pthread_mutex_t *mutex,
const char *file,
const int line);
85 static void insertLock(pthread_mutex_t *mutex,
const long long threadId,
const char *file,
const int line);
87 static void setMaxBlockThreads(
int blockNum) { mMaxBlockTids = blockNum; }
90 static set<pthread_mutex_t *> mEnableRecurisives;
93 static map<pthread_mutex_t *, LockID> mLocks;
94 static map<pthread_mutex_t *, int> mWaitTimes;
95 static map<long long, pthread_mutex_t *> mWaitLocks;
96 static map<long long, set<pthread_mutex_t *>> mOwnLocks;
98 static pthread_rwlock_t mMapMutex;
99 static int mMaxBlockTids;
105#define MUTEXT_STATIC_INIT() PTHREAD_MUTEX_INITIALIZER
106#define MUTEX_INIT(lock, attr) pthread_mutex_init(lock, attr)
107#define MUTEX_DESTROY(lock) pthread_mutex_destroy(lock)
108#define MUTEX_LOCK(lock) pthread_mutex_lock(lock)
109#define MUTEX_UNLOCK(lock) pthread_mutex_unlock(lock)
110#define MUTEX_TRYLOCK(lock) pthread_mutex_trylock(lock)
112#define COND_INIT(cond, attr) pthread_cond_init(cond, attr)
113#define COND_DESTROY(cond) pthread_cond_destroy(cond)
114#define COND_WAIT(cond, mutex) pthread_cond_wait(cond, mutex)
115#define COND_WAIT_TIMEOUT(cond, mutex, time, ret) ret = pthread_cond_timedwait(cond, mutex, time)
116#define COND_SIGNAL(cond) pthread_cond_signal(cond)
117#define COND_BRAODCAST(cond) pthread_cond_broadcast(cond)
121#define MUTEX_STATIC_INIT() \
122 PTHREAD_MUTEX_INITIALIZER; \
123 LOG_INFO("PTHREAD_MUTEX_INITIALIZER");
127#define MUTEX_INIT(lock, attr) \
129 LOG_INFO("pthread_mutex_init %p", lock); \
130 if (attr != NULL) { \
132 pthread_mutexattr_gettype(attr, &type); \
133 if (type == PTHREAD_MUTEX_RECURSIVE) { \
134 LockTrace::mEnableRecurisives.insert(lock); \
137 int result = pthread_mutex_init(lock, attr); \
143#define MUTEX_INIT(lock, attr) \
145 LOG_INFO("pthread_mutex_init %p", lock); \
146 if (attr != NULL) { \
148 pthread_mutexattr_gettype(attr, &type); \
149 if (type == PTHREAD_MUTEX_RECURSIVE_NP) { \
150 LockTrace::mEnableRecurisives.insert(lock); \
153 int result = pthread_mutex_init(lock, attr); \
158#define MUTEX_DESTROY(lock) \
160 LockTrace::mEnableRecurisives.erase(lock); \
161 int result = pthread_mutex_destroy(lock); \
162 LOG_INFO("pthread_mutex_destroy %p", lock); \
166#define MUTEX_LOCK(mutex) \
168 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
169 int result = pthread_mutex_lock(mutex); \
170 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
172 LOG_ERROR("Failed to lock %p, rc %d:%s", mutex, errno, strerror(errno)); \
177#define MUTEX_TRYLOCK(mutex) \
179 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
180 int result = pthread_mutex_trylock(mutex); \
182 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
187#define MUTEX_UNLOCK(lock) \
189 int result = pthread_mutex_unlock(lock); \
190 LockTrace::unlock(lock, gettid(), __FILE__, __LINE__); \
191 MUTEX_LOG("mutex:%p has been ulocked", lock); \
193 LOG_ERROR("Failed to unlock %p, rc %d:%s", lock, errno, strerror(errno)); \
198#define COND_INIT(cond, attr) \
200 LOG_INFO("pthread_cond_init"); \
201 int result = pthread_cond_init(cond, attr); \
205#define COND_DESTROY(cond) \
207 int result = pthread_cond_destroy(cond); \
208 LOG_INFO("pthread_cond_destroy"); \
212#define COND_WAIT(cond, mutex) \
214 MUTEX_LOG("pthread_cond_wait, cond:%p, mutex:%p", cond, mutex); \
215 LockTrace::unlock(mutex, gettid(), __FILE__, __LINE__); \
216 int result = pthread_cond_wait(cond, mutex); \
217 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
218 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
219 MUTEX_LOG("Lock %p under pthread_cond_wait", mutex); \
223#define COND_WAIT_TIMEOUT(cond, mutex, time, ret) \
225 MUTEX_LOG("pthread_cond_timedwait, cond:%p, mutex:%p", cond, mutex); \
226 LockTrace::unlock(mutex, gettid(), __FILE__, __LINE__); \
227 int result = pthread_cond_timedwait(cond, mutex, time); \
229 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
230 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
231 MUTEX_LOG("Lock %p under pthread_cond_wait", mutex); \
236#define COND_SIGNAL(cond) \
238 int result = pthread_cond_signal(cond); \
239 MUTEX_LOG("pthread_cond_signal, cond:%p", cond); \
243#define COND_BRAODCAST(cond) \
245 int result = pthread_cond_broadcast(cond); \
246 MUTEX_LOG("pthread_cond_broadcast, cond:%p", cond); \
294 bool try_lock_shared();
295 void unlock_shared();
316 bool try_lock_shared();
317 void unlock_shared();
325 condition_variable shared_lock_cv_;
326 condition_variable exclusive_lock_cv_;
327 int shared_lock_count_ = 0;
328 int exclusive_lock_count_ = 0;
329 thread::id recursive_owner_;
330 int recursive_count_ = 0;