Commit ebc611da authored by Steven Murray's avatar Steven Murray
Browse files

Added cta::threading::RWLock

parent 622ec286
......@@ -124,6 +124,9 @@ set (COMMON_LIB_SRC_FILES
threading/CondVar.cpp
threading/Daemon.cpp
threading/Mutex.cpp
threading/RWLock.cpp
threading/RWLockRdLocker.cpp
threading/RWLockWrLocker.cpp
threading/SocketPair.cpp
threading/System.cpp
threading/Thread.cpp
......@@ -173,6 +176,7 @@ set (COMMON_UNIT_TESTS_LIB_SRC_FILES
CRCTest.cpp
threading/CondVarTest.cpp
threading/DaemonTest.cpp
threading/RWLockTest.cpp
threading/SocketPairTest.cpp
threading/ThreadingBlockingQTests.cpp
# threading/ThreadingMPTests.cpp is commented out because of errors caused by libust
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/threading/RWLock.hpp"
#include "common/exception/Exception.hpp"
#include "common/utils/utils.hpp"
namespace cta {
namespace threading {
//------------------------------------------------------------------------------
//constructor
//------------------------------------------------------------------------------
RWLock::RWLock() {
const int rc = pthread_rwlock_init(&m_lock, nullptr);
if(0 != rc) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: Failed to initialise underlying pthread read-write lock: " <<
utils::errnoToString(rc);
throw ex;
}
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
RWLock::~RWLock() {
pthread_rwlock_destroy(&m_lock);
}
//------------------------------------------------------------------------------
// rdlock
//------------------------------------------------------------------------------
void RWLock::rdlock() {
const int rc = pthread_rwlock_rdlock(&m_lock);
if(0 != rc) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: Failed to take read lock on underlying pthread read-write lock: "
<< utils::errnoToString(rc);
throw ex;
}
}
//------------------------------------------------------------------------------
// wrlock
//------------------------------------------------------------------------------
void RWLock::wrlock() {
const int rc = pthread_rwlock_wrlock(&m_lock);
if(0 != rc) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: Failed to take write lock on underlying pthread read-write lock: "
<< utils::errnoToString(rc);
throw ex;
}
}
//------------------------------------------------------------------------------
//unlock
//------------------------------------------------------------------------------
void RWLock::unlock() {
const int rc = pthread_rwlock_unlock(&m_lock);
if(0 != rc) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: Failed to unlock underlying pthread read-write lock: " <<
utils::errnoToString(rc);
throw ex;
}
}
} // namespace threading
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <pthread.h>
namespace cta {
namespace threading {
/**
* A C++ wrapper around a pthdead read-write lock.
* variable.
*/
class RWLock {
public:
RWLock();
~RWLock();
void rdlock();
void wrlock();
void unlock();
private:
pthread_rwlock_t m_lock;
};
} // namespace threading
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/exception/Exception.hpp"
#include "common/threading/RWLock.hpp"
#include "common/threading/RWLockRdLocker.hpp"
namespace cta {
namespace threading {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
RWLockRdLocker::RWLockRdLocker(RWLock &lock): m_lock(lock) {
try {
m_lock.rdlock();
} catch(exception::Exception &ne) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed to take read lock: " << ne.getMessage().str();
throw ex;
}
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
RWLockRdLocker::~RWLockRdLocker() {
m_lock.unlock();
}
} // namespace threading
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace cta {
namespace threading {
class RWLock;
/**
* A scoped read lock on an RWLock.
*/
class RWLockRdLocker {
public:
/**
* Constructor.
*
* Takes a read lock on the specified read-write lock.
*
* @param lock The read-write lock on which to take a read-lock.
*/
RWLockRdLocker(RWLock &lock);
/**
* Destructor.
*
* Releases the read lock.
*/
~RWLockRdLocker();
private:
/**
* The read-write lock.
*/
RWLock &m_lock;
}; // class RWLockRdLocker
} // namespace threading
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
#include <iostream>
#include "common/threading/RWLock.hpp"
#include "common/threading/RWLockRdLocker.hpp"
#include "common/threading/RWLockWrLocker.hpp"
#include "common/threading/Thread.hpp"
namespace unitTests {
class cta_threading_RWLockTest : public ::testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
}
class RdLockerThread: public ::cta::threading::Thread {
public:
RdLockerThread(cta::threading::RWLock &lock, uint32_t &counter): m_lock(lock), m_counter(counter) {
}
void run() {
cta::threading::RWLockRdLocker rdLocker(m_lock);
// Just read the counter - do not write to it
uint32_t copyOfCounter = m_counter;
copyOfCounter++;
}
private:
cta::threading::RWLock &m_lock;
uint32_t &m_counter;
};
class WrLockerThread: public ::cta::threading::Thread {
public:
WrLockerThread(cta::threading::RWLock &lock, uint32_t &counter): m_lock(lock), m_counter(counter) {
}
void run() {
cta::threading::RWLockWrLocker wrLocker(m_lock);
m_counter++;
}
private:
cta::threading::RWLock &m_lock;
uint32_t &m_counter;
};
};
TEST_F(cta_threading_RWLockTest, rdlock) {
using namespace cta::threading;
RWLock lock;
lock.rdlock();
lock.unlock();
}
TEST_F(cta_threading_RWLockTest, wrlock) {
using namespace cta::threading;
RWLock lock;
lock.wrlock();
lock.unlock();
}
TEST_F(cta_threading_RWLockTest, RWLockRdLocker) {
using namespace cta::threading;
RWLock lock;
RWLockRdLocker rdLocker(lock);
}
TEST_F(cta_threading_RWLockTest, RWLockWrLocker) {
using namespace cta::threading;
RWLock lock;
RWLockWrLocker wrLocker(lock);
}
TEST_F(cta_threading_RWLockTest, multiple_threads) {
using namespace cta::threading;
RWLock lock;
uint32_t counter = 0;
RdLockerThread rdLockerThreads[4] = {{lock, counter}, {lock, counter}, {lock, counter}, {lock, counter}};
WrLockerThread wrLockerThreads[4] = {{lock, counter}, {lock, counter}, {lock, counter}, {lock, counter}};
for(uint32_t i = 0; i <4; i++) {
rdLockerThreads[i].start();
wrLockerThreads[i].start();
}
for(uint32_t i = 0; i <4; i++) {
rdLockerThreads[i].wait();
wrLockerThreads[i].wait();
}
ASSERT_EQ(4, counter);
}
} // namespace unitTests
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/exception/Exception.hpp"
#include "common/threading/RWLock.hpp"
#include "common/threading/RWLockWrLocker.hpp"
namespace cta {
namespace threading {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
RWLockWrLocker::RWLockWrLocker(RWLock &lock): m_lock(lock) {
try {
m_lock.wrlock();
} catch(exception::Exception &ne) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed to take write lock: " << ne.getMessage().str();
throw ex;
}
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
RWLockWrLocker::~RWLockWrLocker() {
m_lock.unlock();
}
} // namespace threading
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace cta {
namespace threading {
class RWLock;
/**
* A scoped read lock on an RWLock.
*/
class RWLockWrLocker {
public:
/**
* Constructor.
*
* Takes a write lock on the specified read-write lock.
*
* @param lock The read-write lock on which to take a read-lock.
*/
RWLockWrLocker(RWLock &lock);
/**
* Destructor.
*
* Releases the write lock.
*/
~RWLockWrLocker();
private:
/**
* The read-write lock.
*/
RWLock &m_lock;
}; // class RWLockWrLocker
} // namespace threading
} // namespace cta
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment