// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/os.h"
#include "vm/thread.h"
#include "vm/thread_pool.h"
#include "vm/unit_test.h"

namespace dart {

DECLARE_FLAG(int, worker_timeout_millis);


class ThreadPoolTestPeer {
 public:
  // When the pool has an exit monitor, workers notify a monitor just
  // before they exit.  This is only used in tests to make sure that
  // Shutdown works.
  static void SetExitMonitor(Monitor* exit_monitor, int* exit_count) {
    ThreadPool::exit_monitor_ = exit_monitor;
    ThreadPool::exit_count_ = exit_count;
  }
};


UNIT_TEST_CASE(ThreadPool_Create) {
  ThreadPool thread_pool;
}


class TestTask : public ThreadPool::Task {
 public:
  TestTask(Monitor* sync, bool* done)
      : sync_(sync), done_(done) {
  }

  void Run() {
    MonitorLocker ml(sync_);
    *done_ = true;
    ml.Notify();
  }

 private:
  Monitor* sync_;
  bool* done_;
};


UNIT_TEST_CASE(ThreadPool_RunOne) {
  ThreadPool thread_pool;
  Monitor sync;
  bool done = false;
  thread_pool.Run(new TestTask(&sync, &done));
  {
    MonitorLocker ml(&sync);
    while (!done) {
      ml.Wait();
    }
  }
  EXPECT(done);

  // Do a sanity test on the worker stats.
  EXPECT_EQ(1U, thread_pool.workers_started());
  EXPECT_EQ(0U, thread_pool.workers_stopped());
}


UNIT_TEST_CASE(ThreadPool_RunMany) {
  const int kTaskCount = 100;
  ThreadPool thread_pool;
  Monitor sync[kTaskCount];
  bool done[kTaskCount];

  for (int i = 0; i < kTaskCount; i++) {
    done[i] = false;
    thread_pool.Run(new TestTask(&sync[i], &done[i]));
  }
  for (int i = 0; i < kTaskCount; i++) {
    MonitorLocker ml(&sync[i]);
    while (!done[i]) {
      ml.Wait();
    }
    EXPECT(done[i]);
  }
}


class SleepTask : public ThreadPool::Task {
 public:
  explicit SleepTask(int millis)
      : millis_(millis) {
  }

  void Run() {
    OS::Sleep(millis_);
  }

 private:
  int millis_;
};


UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
  Monitor exit_sync;
  int exit_count = 0;
  MonitorLocker ml(&exit_sync);

  // Set up the ThreadPool so that workers notify before they exit.
  ThreadPool* thread_pool = new ThreadPool();
  ThreadPoolTestPeer::SetExitMonitor(&exit_sync, &exit_count);

  // Run a single task.
  thread_pool->Run(new SleepTask(2));

  // Kill the thread pool.
  delete thread_pool;
  thread_pool = NULL;

  // Wait for the workers to terminate.
  while (exit_count == 0) {
    ml.Wait();
  }
  EXPECT_EQ(1, exit_count);
}


UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
  // Adjust the worker timeout so that we timeout quickly.
  int saved_timeout = FLAG_worker_timeout_millis;
  FLAG_worker_timeout_millis = 1;

  ThreadPool thread_pool;
  EXPECT_EQ(0U, thread_pool.workers_started());
  EXPECT_EQ(0U, thread_pool.workers_stopped());

  // Run a worker.
  Monitor sync;
  bool done = false;
  thread_pool.Run(new TestTask(&sync, &done));
  EXPECT_EQ(1U, thread_pool.workers_started());
  EXPECT_EQ(0U, thread_pool.workers_stopped());
  {
    MonitorLocker ml(&sync);
    while (!done) {
      ml.Wait();
    }
  }
  EXPECT(done);

  // Wait up to 5 seconds to see if a worker times out.
  const int kMaxWait = 5000;
  int waited = 0;
  while (thread_pool.workers_stopped() == 0 && waited < kMaxWait) {
    OS::Sleep(1);
    waited += 1;
  }
  EXPECT_EQ(1U, thread_pool.workers_stopped());
  FLAG_worker_timeout_millis = saved_timeout;
}


class SpawnTask : public ThreadPool::Task {
 public:
  SpawnTask(ThreadPool* pool, Monitor* sync, int todo, int total, int* done)
      : pool_(pool), sync_(sync), todo_(todo), total_(total), done_(done) {
  }

  void Run() {
    todo_--;  // Subtract one for current task.
    int child_todo = todo_ / 2;

    // Spawn 0-2 children.
    if (todo_ > 0) {
      pool_->Run(
          new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_));
    }
    if (todo_ > 1) {
      pool_->Run(
          new SpawnTask(pool_, sync_, child_todo, total_, done_));
    }

    {
      MonitorLocker ml(sync_);
      (*done_)++;
      if (*done_ >= total_) {
        ml.Notify();
      }
    }
  }

 private:
  ThreadPool* pool_;
  Monitor* sync_;
  int todo_;
  int total_;
  int* done_;
};


UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
  ThreadPool thread_pool;
  Monitor sync;
  const int kTotalTasks = 500;
  int done = 0;
  thread_pool.Run(
      new SpawnTask(&thread_pool, &sync, kTotalTasks, kTotalTasks, &done));
  {
    MonitorLocker ml(&sync);
    while (done < kTotalTasks) {
      ml.Wait();
    }
  }
  EXPECT_EQ(kTotalTasks, done);
}


}  // namespace dart
