2014-05-13 18:00:26 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2016-04-26 03:13:22 -07:00
|
|
|
#include <memory>
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
#include "webrtc/base/common.h"
|
|
|
|
|
#include "webrtc/base/gunit.h"
|
2016-10-05 15:58:12 -07:00
|
|
|
#include "webrtc/base/event.h"
|
2014-05-13 18:00:26 +00:00
|
|
|
#include "webrtc/base/messagehandler.h"
|
|
|
|
|
#include "webrtc/base/messagequeue.h"
|
|
|
|
|
#include "webrtc/base/sharedexclusivelock.h"
|
|
|
|
|
#include "webrtc/base/thread.h"
|
|
|
|
|
#include "webrtc/base/timeutils.h"
|
|
|
|
|
|
|
|
|
|
namespace rtc {
|
|
|
|
|
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kMsgRead = 0;
|
|
|
|
|
static const uint32_t kMsgWrite = 0;
|
2014-05-13 18:00:26 +00:00
|
|
|
static const int kNoWaitThresholdInMs = 10;
|
|
|
|
|
static const int kWaitThresholdInMs = 80;
|
|
|
|
|
static const int kProcessTimeInMs = 100;
|
|
|
|
|
static const int kProcessTimeoutInMs = 5000;
|
|
|
|
|
|
|
|
|
|
class SharedExclusiveTask : public MessageHandler {
|
|
|
|
|
public:
|
|
|
|
|
SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock,
|
|
|
|
|
int* value,
|
2016-10-05 15:58:12 -07:00
|
|
|
Event* done)
|
2014-05-13 18:00:26 +00:00
|
|
|
: shared_exclusive_lock_(shared_exclusive_lock),
|
|
|
|
|
value_(value),
|
|
|
|
|
done_(done) {
|
|
|
|
|
worker_thread_.reset(new Thread());
|
|
|
|
|
worker_thread_->Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<Thread> worker_thread_;
|
2014-05-13 18:00:26 +00:00
|
|
|
SharedExclusiveLock* shared_exclusive_lock_;
|
|
|
|
|
int* value_;
|
2016-10-05 15:58:12 -07:00
|
|
|
Event* done_;
|
2014-05-13 18:00:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ReadTask : public SharedExclusiveTask {
|
|
|
|
|
public:
|
2016-10-05 15:58:12 -07:00
|
|
|
ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done)
|
2014-05-13 18:00:26 +00:00
|
|
|
: SharedExclusiveTask(shared_exclusive_lock, value, done) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostRead(int* value) {
|
2016-06-10 14:17:27 -07:00
|
|
|
worker_thread_->Post(RTC_FROM_HERE, this, kMsgRead,
|
|
|
|
|
new TypedMessageData<int*>(value));
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
virtual void OnMessage(Message* message) {
|
|
|
|
|
ASSERT(rtc::Thread::Current() == worker_thread_.get());
|
|
|
|
|
ASSERT(message != NULL);
|
|
|
|
|
ASSERT(message->message_id == kMsgRead);
|
|
|
|
|
|
|
|
|
|
TypedMessageData<int*>* message_data =
|
|
|
|
|
static_cast<TypedMessageData<int*>*>(message->pdata);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
SharedScope ss(shared_exclusive_lock_);
|
|
|
|
|
*message_data->data() = *value_;
|
2016-10-05 15:58:12 -07:00
|
|
|
done_->Set();
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
delete message->pdata;
|
|
|
|
|
message->pdata = NULL;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class WriteTask : public SharedExclusiveTask {
|
|
|
|
|
public:
|
2016-10-05 15:58:12 -07:00
|
|
|
WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done)
|
2014-05-13 18:00:26 +00:00
|
|
|
: SharedExclusiveTask(shared_exclusive_lock, value, done) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostWrite(int value) {
|
2016-06-10 14:17:27 -07:00
|
|
|
worker_thread_->Post(RTC_FROM_HERE, this, kMsgWrite,
|
|
|
|
|
new TypedMessageData<int>(value));
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
virtual void OnMessage(Message* message) {
|
|
|
|
|
ASSERT(rtc::Thread::Current() == worker_thread_.get());
|
|
|
|
|
ASSERT(message != NULL);
|
|
|
|
|
ASSERT(message->message_id == kMsgWrite);
|
|
|
|
|
|
|
|
|
|
TypedMessageData<int>* message_data =
|
|
|
|
|
static_cast<TypedMessageData<int>*>(message->pdata);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
ExclusiveScope es(shared_exclusive_lock_);
|
|
|
|
|
*value_ = message_data->data();
|
2016-10-05 15:58:12 -07:00
|
|
|
done_->Set();
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
delete message->pdata;
|
|
|
|
|
message->pdata = NULL;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Unit test for SharedExclusiveLock.
|
|
|
|
|
class SharedExclusiveLockTest
|
|
|
|
|
: public testing::Test {
|
|
|
|
|
public:
|
|
|
|
|
SharedExclusiveLockTest() : value_(0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void SetUp() {
|
|
|
|
|
shared_exclusive_lock_.reset(new SharedExclusiveLock());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<SharedExclusiveLock> shared_exclusive_lock_;
|
2014-05-13 18:00:26 +00:00
|
|
|
int value_;
|
|
|
|
|
};
|
|
|
|
|
|
2014-10-09 22:08:15 +00:00
|
|
|
TEST_F(SharedExclusiveLockTest, TestSharedShared) {
|
2014-05-13 18:00:26 +00:00
|
|
|
int value0, value1;
|
2016-10-05 15:58:12 -07:00
|
|
|
Event done0(false, false), done1(false, false);
|
2014-05-13 18:00:26 +00:00
|
|
|
ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
|
|
|
|
|
ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1);
|
|
|
|
|
|
|
|
|
|
// Test shared locks can be shared without waiting.
|
|
|
|
|
{
|
|
|
|
|
SharedScope ss(shared_exclusive_lock_.get());
|
|
|
|
|
value_ = 1;
|
|
|
|
|
reader0.PostRead(&value0);
|
|
|
|
|
reader1.PostRead(&value1);
|
|
|
|
|
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_TRUE(done0.Wait(kProcessTimeoutInMs));
|
|
|
|
|
EXPECT_TRUE(done1.Wait(kProcessTimeoutInMs));
|
|
|
|
|
EXPECT_EQ(1, value0);
|
|
|
|
|
EXPECT_EQ(1, value1);
|
|
|
|
|
}
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-05 15:58:12 -07:00
|
|
|
TEST_F(SharedExclusiveLockTest, TestSharedExclusive) {
|
|
|
|
|
Event done(false, false);
|
2014-05-13 18:00:26 +00:00
|
|
|
WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
|
|
|
|
|
|
|
|
|
|
// Test exclusive lock needs to wait for shared lock.
|
|
|
|
|
{
|
|
|
|
|
SharedScope ss(shared_exclusive_lock_.get());
|
|
|
|
|
value_ = 1;
|
|
|
|
|
writer.PostWrite(2);
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_FALSE(done.Wait(kProcessTimeInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
EXPECT_EQ(2, value_);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 22:08:15 +00:00
|
|
|
TEST_F(SharedExclusiveLockTest, TestExclusiveShared) {
|
2014-05-13 18:00:26 +00:00
|
|
|
int value;
|
2016-10-05 15:58:12 -07:00
|
|
|
Event done(false, false);
|
2014-05-13 18:00:26 +00:00
|
|
|
ReadTask reader(shared_exclusive_lock_.get(), &value_, &done);
|
|
|
|
|
|
|
|
|
|
// Test shared lock needs to wait for exclusive lock.
|
|
|
|
|
{
|
|
|
|
|
ExclusiveScope es(shared_exclusive_lock_.get());
|
|
|
|
|
value_ = 1;
|
|
|
|
|
reader.PostRead(&value);
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_FALSE(done.Wait(kProcessTimeInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
value_ = 2;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
EXPECT_EQ(2, value);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 15:58:12 -07:00
|
|
|
TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) {
|
|
|
|
|
Event done(false, false);
|
2014-05-13 18:00:26 +00:00
|
|
|
WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
|
|
|
|
|
|
|
|
|
|
// Test exclusive lock needs to wait for exclusive lock.
|
|
|
|
|
{
|
|
|
|
|
ExclusiveScope es(shared_exclusive_lock_.get());
|
2016-10-05 15:58:12 -07:00
|
|
|
// Start the writer task only after holding the lock, to ensure it need
|
2014-05-13 18:00:26 +00:00
|
|
|
value_ = 1;
|
|
|
|
|
writer.PostWrite(2);
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_FALSE(done.Wait(kProcessTimeInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
EXPECT_EQ(1, value_);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 15:58:12 -07:00
|
|
|
EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
|
2014-05-13 18:00:26 +00:00
|
|
|
EXPECT_EQ(2, value_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace rtc
|