blob: 583ef0aef56fe4bcec77f630148d9d7da28f8eea [file] [log] [blame]
// Copyright 2010 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVTOOLS_GOMA_BASE_LOCKHELPER_H_
#define DEVTOOLS_GOMA_BASE_LOCKHELPER_H_
#include "absl/base/thread_annotations.h"
#include "basictypes.h"
#ifdef __MACH__
# include <libkern/OSAtomic.h>
#endif
#ifdef _WIN32
# include "config_win.h"
typedef CRITICAL_SECTION OSLockType;
typedef SRWLOCK OSRWLockType;
#else
# include <pthread.h>
# include <errno.h>
typedef pthread_mutex_t OSLockType;
typedef pthread_rwlock_t OSRWLockType;
#endif
namespace devtools_goma {
// NOTE: capability based thread safety analysis is not working well
// for shared lock. So, let me keep using older style thread safety analysis.
class LOCKABLE Lock {
public:
Lock();
~Lock();
// If the lock is not held, take it and return true. If the lock is already
// held by something else, immediately return false.
bool Try() EXCLUSIVE_TRYLOCK_FUNCTION(true);
// Take the lock, blocking until it is available if necessary.
void Acquire() EXCLUSIVE_LOCK_FUNCTION();
// Release the lock. This must only be called by the lock's holder: after
// a successful call to Try, or a call to Lock.
void Release() UNLOCK_FUNCTION();
private:
friend class ConditionVariable;
#ifdef _WIN32
friend class WinVistaCondVar;
#endif
OSLockType os_lock_;
DISALLOW_COPY_AND_ASSIGN(Lock);
};
#ifdef __MACH__
// In Mac, pthread becomes very slow when contention happens.
// Using OSSpinLock improves performance for short lock holding.
class LOCKABLE FastLock {
public:
FastLock(const FastLock&) = delete;
FastLock& operator=(const FastLock&) = delete;
FastLock() : lock_(OS_SPINLOCK_INIT) {}
void Acquire() EXCLUSIVE_LOCK_FUNCTION() {
OSSpinLockLock(&lock_);
}
void Release() UNLOCK_FUNCTION() {
OSSpinLockUnlock(&lock_);
}
private:
// TODO: Use os_unfair_lock if available.
// OSSpinLock is deprecated in 10.12.
OSSpinLock lock_;
};
#else
using FastLock = Lock;
#endif
// ReadWriteLock provides readers-writer lock.
class LOCKABLE ReadWriteLock {
public:
ReadWriteLock();
~ReadWriteLock();
void AcquireShared() SHARED_LOCK_FUNCTION();
void ReleaseShared() UNLOCK_FUNCTION();
void AcquireExclusive() EXCLUSIVE_LOCK_FUNCTION();
void ReleaseExclusive() UNLOCK_FUNCTION();
private:
#ifdef _WIN32
SRWLOCK srw_lock_;
#else
OSRWLockType os_rwlock_;
#endif
DISALLOW_COPY_AND_ASSIGN(ReadWriteLock);
};
class SCOPED_LOCKABLE AutoLock {
public:
// Does not take ownership of |lock|, which must refer to a valid Lock
// that outlives this object.
explicit AutoLock(Lock* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
: lock_(lock) {
lock_->Acquire();
}
~AutoLock() UNLOCK_FUNCTION() {
lock_->Release();
}
private:
Lock* lock_;
DISALLOW_COPY_AND_ASSIGN(AutoLock);
};
class SCOPED_LOCKABLE AutoFastLock {
public:
AutoFastLock(const AutoFastLock&) = delete;
AutoFastLock& operator=(const AutoFastLock&) = delete;
// Does not take ownership of |lock|, which must refer to a valid FastLock
// that outlives this object.
explicit AutoFastLock(FastLock* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
: lock_(lock) {
lock_->Acquire();
}
~AutoFastLock() UNLOCK_FUNCTION() {
lock_->Release();
}
private:
FastLock* lock_;
};
class SCOPED_LOCKABLE AutoExclusiveLock {
public:
// Does not take ownership of |lock|, which must refer to a valid
// ReadWriteLock that outlives this object.
explicit AutoExclusiveLock(ReadWriteLock* lock)
EXCLUSIVE_LOCK_FUNCTION(lock) : lock_(lock) {
lock_->AcquireExclusive();
}
~AutoExclusiveLock() UNLOCK_FUNCTION() {
lock_->ReleaseExclusive();
}
private:
ReadWriteLock* lock_;
DISALLOW_COPY_AND_ASSIGN(AutoExclusiveLock);
};
class SCOPED_LOCKABLE AutoSharedLock {
public:
// Does not take ownership of |lock|, which must refer to a valid
// ReadWriteLock that outlives this object.
explicit AutoSharedLock(ReadWriteLock* lock) SHARED_LOCK_FUNCTION(lock)
: lock_(lock) {
lock_->AcquireShared();
}
~AutoSharedLock() UNLOCK_FUNCTION() {
lock_->ReleaseShared();
}
private:
ReadWriteLock* lock_;
DISALLOW_COPY_AND_ASSIGN(AutoSharedLock);
};
// POSIX conditional variable
class ConditionVariable {
public:
ConditionVariable();
~ConditionVariable();
void Wait(Lock* lock);
void Signal();
void Broadcast();
private:
#ifdef _WIN32
CONDITION_VARIABLE cv_;
#else // Assume POSIX
pthread_cond_t condition_;
#endif
DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
};
} // namespace devtools_goma
#endif // DEVTOOLS_GOMA_BASE_LOCKHELPER_H_