blob: 295e643f066296bacd16e36ec7d75edc0e97e198 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef BTHREAD_RWLOCK_H
#define BTHREAD_RWLOCK_H
#include "bthread/types.h"
#include "bthread/bthread.h"
#include "butil/scoped_lock.h"
namespace bthread {
// The C++ Wrapper of bthread_rwlock
// NOTE: Not aligned to cacheline as the container of RWLock is practically aligned.
class RWLock {
public:
typedef bthread_rwlock_t* native_handler_type;
RWLock() {
int rc = bthread_rwlock_init(&_rwlock, NULL);
if (rc) {
throw std::system_error(std::error_code(rc, std::system_category()),
"RWLock constructor failed");
}
}
~RWLock() {
CHECK_EQ(0, bthread_rwlock_destroy(&_rwlock));
}
DISALLOW_COPY_AND_ASSIGN(RWLock);
native_handler_type native_handler() { return &_rwlock; }
void rdlock() {
int rc = bthread_rwlock_rdlock(&_rwlock);
if (rc) {
throw std::system_error(std::error_code(rc, std::system_category()),
"RWLock rdlock failed");
}
}
bool try_rdlock() {
return 0 == bthread_rwlock_tryrdlock(&_rwlock);
}
bool timed_rdlock(const struct timespec* abstime) {
return 0 == bthread_rwlock_timedrdlock(&_rwlock, abstime);
}
void wrlock() {
int rc = bthread_rwlock_wrlock(&_rwlock);
if (rc) {
throw std::system_error(std::error_code(rc, std::system_category()),
"RWLock wrlock failed");
}
}
bool try_wrlock() {
return 0 == bthread_rwlock_trywrlock(&_rwlock);
}
bool timed_wrlock(const struct timespec* abstime) {
return 0 == bthread_rwlock_timedwrlock(&_rwlock, abstime);
}
void unlock() { bthread_rwlock_unlock(&_rwlock); }
private:
bthread_rwlock_t _rwlock{};
};
// Read lock guard of rwlock.
class RWLockRdGuard {
public:
explicit RWLockRdGuard(bthread_rwlock_t& rwlock)
: _rwlock(&rwlock) {
#if !defined(NDEBUG)
const int rc = bthread_rwlock_rdlock(_rwlock);
if (rc) {
LOG(FATAL) << "Fail to rdlock bthread_rwlock_t=" << _rwlock << ", " << berror(rc);
_rwlock = NULL;
}
#else
bthread_rwlock_rdlock(_rwlock);
#endif // NDEBUG
}
explicit RWLockRdGuard(RWLock& rwlock)
: RWLockRdGuard(*rwlock.native_handler()) {}
~RWLockRdGuard() {
#ifndef NDEBUG
if (NULL != _rwlock) {
bthread_rwlock_unlock(_rwlock);
}
#else
bthread_rwlock_unlock(_rwlock);
#endif // NDEBUG
}
DISALLOW_COPY_AND_ASSIGN(RWLockRdGuard);
private:
bthread_rwlock_t* _rwlock;
};
// Write lock guard of rwlock.
class RWLockWrGuard {
public:
explicit RWLockWrGuard(bthread_rwlock_t& rwlock)
: _rwlock(&rwlock) {
#if !defined(NDEBUG)
const int rc = bthread_rwlock_wrlock(_rwlock);
if (rc) {
LOG(FATAL) << "Fail to wrlock bthread_rwlock_t=" << _rwlock << ", " << berror(rc);
_rwlock = NULL;
}
#else
bthread_rwlock_wrlock(_rwlock);
#endif // NDEBUG
}
explicit RWLockWrGuard(RWLock& rwlock)
: RWLockWrGuard(*rwlock.native_handler()) {}
~RWLockWrGuard() {
#ifndef NDEBUG
if (NULL != _rwlock) {
bthread_rwlock_unlock(_rwlock);
}
#else
bthread_rwlock_unlock(_rwlock);
#endif // NDEBUG
}
DISALLOW_COPY_AND_ASSIGN(RWLockWrGuard);
private:
bthread_rwlock_t* _rwlock;
};
} // namespace bthread
namespace std {
template <>
class lock_guard<bthread_rwlock_t> {
public:
lock_guard(bthread_rwlock_t& rwlock, bool read)
:_rwlock(&rwlock), _read(read) {
#if !defined(NDEBUG)
int rc;
if (_read) {
rc = bthread_rwlock_rdlock(_rwlock);
} else {
rc = bthread_rwlock_wrlock(_rwlock);
}
if (rc) {
LOG(FATAL) << "Fail to lock bthread_rwlock_t=" << _rwlock << ", " << berror(rc);
_rwlock = NULL;
}
#else
if (_read) {
bthread_rwlock_rdlock(_rwlock);
} else {
bthread_rwlock_wrlock(_rwlock);
}
#endif // NDEBUG
}
~lock_guard() {
#ifndef NDEBUG
if (NULL != _rwlock) {
bthread_rwlock_unlock(_rwlock);
}
#else
bthread_rwlock_unlock(_rwlock);
#endif // NDEBUG
}
DISALLOW_COPY_AND_ASSIGN(lock_guard);
private:
bthread_rwlock_t* _rwlock;
bool _read;
};
template <>
class lock_guard<bthread::RWLock> {
public:
lock_guard(bthread::RWLock& rwlock, bool read)
:_rwlock_guard(*rwlock.native_handler(), read) {}
DISALLOW_COPY_AND_ASSIGN(lock_guard);
private:
std::lock_guard<bthread_rwlock_t> _rwlock_guard;
};
} // namespace std
#endif //BTHREAD_RWLOCK_H