blob: d0d682d6344ca8325d028a7c72ef3289449ba774 [file] [log] [blame]
// Licensed 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
#include <gtest/gtest.h>
#include <process/future.hpp>
#include <process/rwlock.hpp>
using process::Future;
using process::ReadWriteLock;
TEST(ReadWriteLockTest, LockWhenUnlocked)
{
ReadWriteLock lock;
// We should be able to lock for writing or reading when the
// lock is unlocked.
EXPECT_TRUE(lock.write_lock().isReady());
lock.write_unlock();
EXPECT_TRUE(lock.read_lock().isReady());
lock.read_unlock();
EXPECT_TRUE(lock.write_lock().isReady());
lock.write_unlock();
}
TEST(ReadWriteLockTest, BlockReads)
{
ReadWriteLock lock;
// We should be able to acquire the write lock immediately.
EXPECT_TRUE(lock.write_lock().isReady());
// Subsequent reads should "block".
Future<Nothing> read = lock.read_lock();
EXPECT_TRUE(read.isPending());
// After we release the write lock,
// the read lock will be acquired.
lock.write_unlock();
EXPECT_TRUE(read.isReady());
lock.read_unlock();
}
TEST(ReadWriteLockTest, BlockWrites)
{
ReadWriteLock lock;
// We should be able to acquire the write lock immediately.
EXPECT_TRUE(lock.write_lock().isReady());
// Subsequent writes should "block".
Future<Nothing> write = lock.write_lock();
EXPECT_TRUE(write.isPending());
// After we release the write lock,
// the next write lock will be acquired.
lock.write_unlock();
EXPECT_TRUE(write.isReady());
lock.write_unlock();
// The write lock should also "block" behind a read lock.
EXPECT_TRUE(lock.read_lock().isReady());
write = lock.write_lock();
EXPECT_TRUE(write.isPending());
// After we release the read lock,
// the next write lock will be acquired.
lock.read_unlock();
EXPECT_TRUE(write.isReady());
lock.write_unlock();
}
TEST(ReadWriteLockTest, ConcurrentReads)
{
ReadWriteLock lock;
// We should be able to acquire read lock multiple times.
EXPECT_TRUE(lock.read_lock().isReady());
EXPECT_TRUE(lock.read_lock().isReady());
EXPECT_TRUE(lock.read_lock().isReady());
// Subsequent writes should "block" and won't be unblocked
// until all reads complete.
Future<Nothing> write = lock.write_lock();
EXPECT_TRUE(write.isPending());
lock.read_unlock();
EXPECT_TRUE(write.isPending());
lock.read_unlock();
EXPECT_TRUE(write.isPending());
lock.read_unlock();
EXPECT_TRUE(write.isReady());
lock.write_unlock();
}
TEST(ReadWriteLockTest, NoStarvation)
{
ReadWriteLock lock;
// We should be able to acquire read lock immediately.
EXPECT_TRUE(lock.read_lock().isReady());
// Queue a [WRITE1, READ1, READ2, WRITE2, READ3, READ4].
// The reads will run in groups, but cannot cross
// the write boundaries (i.e. READ3 and READ4 must wait
// behind WRITE2).
Future<Nothing> write1 = lock.write_lock();
EXPECT_TRUE(write1.isPending());
Future<Nothing> read1 = lock.read_lock();
EXPECT_TRUE(read1.isPending());
Future<Nothing> read2 = lock.read_lock();
EXPECT_TRUE(read2.isPending());
Future<Nothing> write2 = lock.write_lock();
EXPECT_TRUE(write2.isPending());
Future<Nothing> read3 = lock.read_lock();
EXPECT_TRUE(read3.isPending());
Future<Nothing> read4 = lock.read_lock();
EXPECT_TRUE(read4.isPending());
// Release the intial read lock.
lock.read_unlock();
EXPECT_TRUE(write1.isReady());
EXPECT_TRUE(read1.isPending());
EXPECT_TRUE(read2.isPending());
EXPECT_TRUE(write2.isPending());
EXPECT_TRUE(read3.isPending());
EXPECT_TRUE(read4.isPending());
lock.write_unlock();
EXPECT_TRUE(read1.isReady());
EXPECT_TRUE(read2.isReady());
EXPECT_TRUE(write2.isPending());
EXPECT_TRUE(read3.isPending());
EXPECT_TRUE(read4.isPending());
lock.read_unlock();
lock.read_unlock();
EXPECT_TRUE(write2.isReady());
EXPECT_TRUE(read3.isPending());
EXPECT_TRUE(read4.isPending());
lock.write_unlock();
EXPECT_TRUE(read3.isReady());
EXPECT_TRUE(read4.isReady());
lock.read_unlock();
lock.read_unlock();
}