This source file includes following definitions.
- satisfiable_flags_
- SetSatisfiedFlags
- SetSatisfiableFlags
- GetType
- CreateEquivalentDispatcherAndCloseImplNoLock
- SatisfiedFlagsNoLock
- SatisfiableFlagsNoLock
- TEST
- TEST
- TEST
- TEST
- TEST
#include "mojo/system/simple_dispatcher.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "mojo/system/test_utils.h"
#include "mojo/system/waiter.h"
#include "mojo/system/waiter_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace system {
namespace {
const int64_t kMicrosPerMs = 1000;
const int64_t kEpsilonMicros = 30 * kMicrosPerMs;
class MockSimpleDispatcher : public SimpleDispatcher {
public:
MockSimpleDispatcher()
: satisfied_flags_(MOJO_WAIT_FLAG_NONE),
satisfiable_flags_(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE) {}
void SetSatisfiedFlags(MojoWaitFlags new_satisfied_flags) {
base::AutoLock locker(lock());
CHECK_EQ(new_satisfied_flags & ~satisfied_flags_,
new_satisfied_flags & ~satisfied_flags_ & satisfiable_flags_);
if (new_satisfied_flags == satisfied_flags_)
return;
satisfied_flags_ = new_satisfied_flags;
StateChangedNoLock();
}
void SetSatisfiableFlags(MojoWaitFlags new_satisfiable_flags) {
base::AutoLock locker(lock());
if (new_satisfiable_flags == satisfiable_flags_)
return;
satisfiable_flags_ = new_satisfiable_flags;
StateChangedNoLock();
}
virtual Type GetType() const OVERRIDE {
return kTypeUnknown;
}
private:
friend class base::RefCountedThreadSafe<MockSimpleDispatcher>;
virtual ~MockSimpleDispatcher() {}
virtual scoped_refptr<Dispatcher>
CreateEquivalentDispatcherAndCloseImplNoLock() OVERRIDE {
scoped_refptr<MockSimpleDispatcher> rv(new MockSimpleDispatcher());
rv->satisfied_flags_ = satisfied_flags_;
rv->satisfiable_flags_ = satisfiable_flags_;
return scoped_refptr<Dispatcher>(rv.get());
}
virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE {
lock().AssertAcquired();
return satisfied_flags_;
}
virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE {
lock().AssertAcquired();
return satisfiable_flags_;
}
MojoWaitFlags satisfied_flags_;
MojoWaitFlags satisfiable_flags_;
DISALLOW_COPY_AND_ASSIGN(MockSimpleDispatcher);
};
TEST(SimpleDispatcherTest, Basic) {
test::Stopwatch stopwatch;
int64_t elapsed_micros;
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
Waiter w;
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
d->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 0));
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 1));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
stopwatch.Start();
EXPECT_EQ(1, w.Wait(MOJO_DEADLINE_INDEFINITE));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 2));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
stopwatch.Start();
EXPECT_EQ(2, w.Wait(0));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 3));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
stopwatch.Start();
EXPECT_EQ(3, w.Wait(2 * kEpsilonMicros));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4));
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4));
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(2 * kEpsilonMicros));
elapsed_micros = stopwatch.Elapsed();
EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
d->RemoveWaiter(&w);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
TEST(SimpleDispatcherTest, BasicUnsatisfiable) {
test::Stopwatch stopwatch;
int64_t elapsed_micros;
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
Waiter w;
w.Init();
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
d->SetSatisfiedFlags(0);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 5));
w.Init();
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6));
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(MOJO_DEADLINE_INDEFINITE));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6));
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(0));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
w.Init();
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 7));
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(2 * kEpsilonMicros));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d->RemoveWaiter(&w);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
TEST(SimpleDispatcherTest, BasicClosed) {
test::Stopwatch stopwatch;
int64_t elapsed_micros;
scoped_refptr<MockSimpleDispatcher> d;
Waiter w;
d = new MockSimpleDispatcher();
w.Init();
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 8));
d = new MockSimpleDispatcher();
w.Init();
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 9));
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(MOJO_DEADLINE_INDEFINITE));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d = new MockSimpleDispatcher();
w.Init();
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 10));
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(0));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
d = new MockSimpleDispatcher();
w.Init();
EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 11));
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
stopwatch.Start();
EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(2 * kEpsilonMicros));
elapsed_micros = stopwatch.Elapsed();
EXPECT_LT(elapsed_micros, kEpsilonMicros);
}
TEST(SimpleDispatcherTest, BasicThreaded) {
test::Stopwatch stopwatch;
bool did_wait;
MojoResult result;
int64_t elapsed_micros;
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
{
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
test::WaiterThread thread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
0,
&did_wait, &result);
stopwatch.Start();
thread.Start();
}
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
elapsed_micros = stopwatch.Elapsed();
EXPECT_FALSE(did_wait);
EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result);
EXPECT_LT(elapsed_micros, kEpsilonMicros);
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
test::WaiterThread thread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
1,
&did_wait, &result);
stopwatch.Start();
thread.Start();
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
elapsed_micros = stopwatch.Elapsed();
EXPECT_TRUE(did_wait);
EXPECT_EQ(1, result);
EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
test::WaiterThread thread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
2,
&did_wait, &result);
stopwatch.Start();
thread.Start();
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_NONE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
elapsed_micros = stopwatch.Elapsed();
EXPECT_TRUE(did_wait);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
test::WaiterThread thread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
3,
&did_wait, &result);
stopwatch.Start();
thread.Start();
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
elapsed_micros = stopwatch.Elapsed();
EXPECT_TRUE(did_wait);
EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
{
test::WaiterThread thread(d,
MOJO_WAIT_FLAG_READABLE,
2 * kEpsilonMicros,
4,
&did_wait, &result);
stopwatch.Start();
thread.Start();
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
}
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
elapsed_micros = stopwatch.Elapsed();
EXPECT_TRUE(did_wait);
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result);
EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
}
TEST(SimpleDispatcherTest, MultipleWaiters) {
static const size_t kNumWaiters = 20;
bool did_wait[kNumWaiters];
MojoResult result[kNumWaiters];
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
ScopedVector<test::WaiterThread> threads;
for (size_t i = 0; i < kNumWaiters; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
for (size_t i = 0; i < kNumWaiters; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
}
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
ScopedVector<test::WaiterThread> threads;
for (size_t i = 0; i < kNumWaiters / 2; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_WRITABLE,
MOJO_DEADLINE_INDEFINITE,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
for (size_t i = 0; i < kNumWaiters / 2; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(MOJO_RESULT_CANCELLED, result[i]);
}
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
ScopedVector<test::WaiterThread> threads;
for (size_t i = 0; i < kNumWaiters / 2; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_READABLE,
MOJO_DEADLINE_INDEFINITE,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_WRITABLE,
MOJO_DEADLINE_INDEFINITE,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
for (size_t i = 0; i < kNumWaiters / 2; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result[i]);
}
{
scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
ScopedVector<test::WaiterThread> threads;
for (size_t i = 0; i < kNumWaiters / 2; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_READABLE,
3 * kEpsilonMicros,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
threads.push_back(new test::WaiterThread(d,
MOJO_WAIT_FLAG_WRITABLE,
1 * kEpsilonMicros,
static_cast<MojoResult>(i),
&did_wait[i], &result[i]));
threads.back()->Start();
}
base::PlatformThread::Sleep(
base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
}
for (size_t i = 0; i < kNumWaiters / 2; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
}
for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
EXPECT_TRUE(did_wait[i]);
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result[i]);
}
}
}
}
}