/*
 * 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.
 */

#include <iostream>
#include <unistd.h>

#include <boost/shared_ptr.hpp>
#include <boost/test/unit_test.hpp>

#include "concurrency/Mutex.h"
#include "concurrency/PosixThreadFactory.h"

using boost::shared_ptr;
using boost::unit_test::test_suite;
using boost::unit_test::framework::master_test_suite;

using namespace apache::thrift::concurrency;
using namespace std;

class Locker : public Runnable
{
protected:
  Locker(boost::shared_ptr<ReadWriteMutex> rwlock, bool writer) :
    rwlock_(rwlock), writer_(writer),
    started_(false), gotLock_(false), signaled_(false) { }

public:
  virtual void run()
  {
    started_ = true;
    if (writer_) {
      rwlock_->acquireWrite();
    } else {
      rwlock_->acquireRead();
    }
    gotLock_ = true;
    while (!signaled_) {
      usleep(5000);
    }
    rwlock_->release();
  }

  bool started() const { return started_; }
  bool gotLock() const { return gotLock_; }
  void signal() { signaled_ = true; }

protected:
  boost::shared_ptr<ReadWriteMutex> rwlock_;
  bool writer_;
  volatile bool started_;
  volatile bool gotLock_;
  volatile bool signaled_;
};

class Reader : public Locker
{
public:
  Reader(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, false) { }
};

class Writer : public Locker
{
public:
  Writer(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, true) { }
};

void test_starve(PosixThreadFactory::POLICY policy)
{
  // the man pages for pthread_wrlock_rdlock suggest that any OS guarantee about
  // writer starvation may be influenced by the scheduling policy, so let's try
  // all 3 policies to see if any of them work.
  PosixThreadFactory factory(policy);
  factory.setDetached(false);

  boost::shared_ptr<ReadWriteMutex> rwlock(new NoStarveReadWriteMutex());

  boost::shared_ptr<Reader> reader1(new Reader(rwlock));
  boost::shared_ptr<Reader> reader2(new Reader(rwlock));
  boost::shared_ptr<Writer> writer(new Writer(rwlock));

  boost::shared_ptr<Thread> treader1 = factory.newThread(reader1);
  boost::shared_ptr<Thread> treader2 = factory.newThread(reader2);
  boost::shared_ptr<Thread> twriter = factory.newThread(writer);

  // launch a reader and make sure he has the lock
  treader1->start();
  while (!reader1->gotLock()) {
    usleep(2000);
  }

  // launch a writer and make sure he's blocked on the lock
  twriter->start();
  while (!writer->started()) {
    usleep(2000);
  }
  // tricky part... we can never be 100% sure that the writer is actually
  // blocked on the lock, but we can pretty reasonably sure because we know
  // he just executed the line immediately before getting the lock, and
  // we'll wait a full second for him to get on it.
  sleep(1);

  // launch a second reader... if the RWMutex guarantees that writers won't
  // starve, this reader should not be able to acquire the lock until the writer
  // has acquired and released it.
  treader2->start();
  while (!reader2->started()) {
    usleep(2000);
  }
  // again... can't be 100% sure the reader is waiting on (or has) the lock
  // but we can be close.
  sleep(1);

  // tell reader 1 to let go of the lock
  reader1->signal();

  // wait for someone to get the lock
  while (!reader2->gotLock() && !writer->gotLock()) {
    usleep(2000);
  }

  // the test succeeded if the WRITER got the lock.
  bool success = writer->gotLock();

  // tell everyone we're done and wait for them to finish
  reader2->signal();
  writer->signal();
  treader1->join();
  treader2->join();
  twriter->join();

  // make sure it worked.
  BOOST_CHECK_MESSAGE(success, "writer is starving");
}

BOOST_AUTO_TEST_SUITE( RWMutexStarveTest )

BOOST_AUTO_TEST_CASE( test_starve_other )
{
  test_starve(PosixThreadFactory::OTHER);
}

BOOST_AUTO_TEST_CASE( test_starve_rr )
{
  test_starve(PosixThreadFactory::ROUND_ROBIN);
}

BOOST_AUTO_TEST_CASE( test_starve_fifo )
{
  test_starve(PosixThreadFactory::FIFO);
}

BOOST_AUTO_TEST_SUITE_END()
