// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "utils.h"

#include <lib/fdio/spawn.h>
#include <lib/fit/defer.h>
#include <lib/zx/clock.h>
#include <lib/zx/process.h>
#include <lib/zx/time.h>
#include <zircon/process.h>
#include <zircon/processargs.h>

#include <zxtest/zxtest.h>

const char* ExternalThread::program_name_ = nullptr;
const char* ExternalThread::helper_flag_ = "futex-owner-helper";

bool WaitFor(zx::duration timeout, WaitFn wait_fn) {
  constexpr zx::duration WAIT_POLL_INTERVAL = zx::msec(1);

  ZX_ASSERT(timeout >= zx::sec(0));
  zx::time deadline = zx::deadline_after(timeout);

  while (!wait_fn()) {
    if (zx::clock::get_monotonic() > deadline) {
      return false;
    }
    zx::nanosleep(zx::deadline_after(WAIT_POLL_INTERVAL));
  }

  return true;
}

zx_koid_t CurrentThreadKoid() {
  zx_info_handle_basic info;
  zx_status_t res = zx_object_get_info(zx_thread_self(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info),
                                       nullptr, nullptr);
  ZX_ASSERT(res == ZX_OK);
  return info.koid;
}

zx_status_t Event::Wait(zx::duration timeout) {
  zx::time deadline = zx::deadline_after(timeout);

  while (signaled_.load(fbl::memory_order_relaxed) == 0) {
    zx_status_t res = zx_futex_wait(&signaled_, 0, ZX_HANDLE_INVALID, deadline.get());
    if ((res != ZX_OK) && (res != ZX_ERR_BAD_STATE)) {
      return res;
    }
  }

  return ZX_OK;
}

void Event::Signal() {
  if (signaled_.load(fbl::memory_order_relaxed) == 0) {
    signaled_.store(1, fbl::memory_order_relaxed);
    zx_futex_wake(&signaled_, UINT32_MAX);
  }
}

void Event::Reset() { signaled_.store(0, fbl::memory_order_relaxed); }

void Thread::Reset() {
  handle_.reset();
  koid_ = ZX_KOID_INVALID;
  SetState(State::WAITING_TO_START);
  thunk_ = nullptr;
  started_evt_.Reset();
  stop_evt_.Reset();
}

void Thread::Start(const char* name, Thunk thunk) {
  ZX_ASSERT(static_cast<bool>(thunk_) == false);

  thunk_ = std::move(thunk);

  auto internal_thunk = [](void* ctx) -> int {
    auto t = reinterpret_cast<Thread*>(ctx);

    // Create a clone of the zx_thread_self handle.  This handle is owned by
    // the runtime, not owned by us.  The runtime will automatically close
    // this handle when the thread exits, invalidating it in the process.
    // If we want to be able to do things like test to see if a thread state
    // has reached DEAD, we need to make our own handle to hold onto.  Do so
    // now.
    //
    // Success or fail, make sure we flag ourselves as started before moving
    // on.  We don't want to hold up the test framework.  They will discover
    // that we failed to start when they check our handle and discover that
    // it failed to duplicate.
    zx::unowned_thread thread_self(zx_thread_self());
    int ret = static_cast<int>(thread_self->duplicate(ZX_RIGHT_SAME_RIGHTS, &(t->handle_)));
    t->koid_ = CurrentThreadKoid();
    t->started_evt_.Signal();

    if (ret == static_cast<int>(ZX_OK)) {
      t->SetState(State::RUNNING);
      ret = t->thunk_();
    }

    t->SetState(State::WAITING_TO_STOP);
    t->stop_evt_.Wait(zx::duration::infinite());
    t->SetState(State::STOPPED);
    return ret;
  };

  int res = thrd_create_with_name(&thread_, internal_thunk, this, name);
  ASSERT_EQ(res, 0);
  ASSERT_OK(started_evt_.Wait(THREAD_TIMEOUT));
  ASSERT_TRUE(handle_.is_valid());
  ASSERT_NE(koid_, ZX_KOID_INVALID);
}

zx_status_t Thread::Stop() {
  if (!handle_.is_valid()) {
    return ZX_ERR_BAD_STATE;
  }

  stop_evt_.Signal();

  zx::time deadline = zx::deadline_after(THREAD_TIMEOUT);
  while (state() != State::STOPPED) {
    if (zx::clock::get_monotonic() > deadline) {
      return ZX_ERR_TIMED_OUT;
    }
    zx::nanosleep(zx::deadline_after(THREAD_POLL_INTERVAL));
  }

  thrd_join(thread_, nullptr);
  Reset();

  return ZX_OK;
}

zx_status_t Thread::GetRunState(uint32_t* run_state) const {
  ZX_DEBUG_ASSERT(run_state != nullptr);
  if (!handle_.is_valid()) {
    return ZX_ERR_BAD_STATE;
  }

  zx_info_thread_t info;
  zx_status_t res = handle_.get_info(ZX_INFO_THREAD, &info, sizeof(info), nullptr, nullptr);
  if (res != ZX_OK) {
    return res;
  }

  *run_state = info.state;
  return ZX_OK;
}

int ExternalThread::DoHelperThread() {
  // Get our channel to our parent from our environment.
  zx::channel remote(zx_take_startup_handle(PA_HND(PA_USER0, 0)));
  if (!remote.is_valid()) {
    return -__LINE__;
  }

  // Duplicate our thread handle.
  zx::unowned_thread cur_thread(zx_thread_self());
  zx::thread thread_copy;
  if (cur_thread->duplicate(ZX_RIGHT_SAME_RIGHTS, &thread_copy) != ZX_OK) {
    return -__LINE__;
  }

  // Send a copy of our thread handle back to our our parent.
  if (zx_handle_t leaked = thread_copy.release();
      remote.write(0, nullptr, 0, &leaked, 1) != ZX_OK) {
    return -__LINE__;
  }

  // Block until our parent closes our control channel, then exit.  Do not
  // block forever... If the worst happens, we don't want to be leaking
  // processes in our test environment.  For now, waiting 2 minutes seems like
  // a Very Long Time to wait for our parent to give us the all clear.
  constexpr zx::duration TIMEOUT(ZX_SEC(120));
  zx_status_t wait_res;
  wait_res = remote.wait_one(ZX_CHANNEL_PEER_CLOSED, zx::deadline_after(TIMEOUT), nullptr);

  return (wait_res == ZX_OK) ? 0 : -__LINE__;
}

void ExternalThread::Start() {
  auto on_failure = fit::defer([this]() { Stop(); });

  // Make sure that we have a program name and have not already started.
  ASSERT_NOT_NULL(program_name_);
  ASSERT_EQ(external_thread_.get(), ZX_HANDLE_INVALID);
  ASSERT_EQ(control_channel_.get(), ZX_HANDLE_INVALID);

  // Create the channel we will use for talking to our external thread.
  zx::channel local, remote;
  ASSERT_OK(zx::channel::create(0, &local, &remote));

  const char* args[] = {program_name_, helper_flag_, nullptr};
  struct fdio_spawn_action transfer_channel_action = {
      .action = FDIO_SPAWN_ACTION_ADD_HANDLE,
      .h = {.id = PA_HND(PA_USER0, 0), .handle = remote.release()}};

  zx::process proc;
  char err_msg_out[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
  zx_status_t res =
      fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, program_name_, args, nullptr, 1,
                     &transfer_channel_action, proc.reset_and_get_address(), err_msg_out);
  ASSERT_OK(res, "%s", err_msg_out);

  // Get our child's thread handle, but do not wait forever.
  constexpr zx::duration TIMEOUT(ZX_MSEC(2500));
  constexpr zx_signals_t WAKE_SIGS = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
  zx_signals_t sigs = 0;
  ASSERT_OK(local.wait_one(WAKE_SIGS, zx::deadline_after(TIMEOUT), &sigs));
  ASSERT_NE(sigs & ZX_CHANNEL_READABLE, 0);

  uint32_t rxed_handles = 0;
  ASSERT_EQ(local.read(0, nullptr, external_thread_.reset_and_get_address(), 0, 1, nullptr,
                       &rxed_handles),
            ZX_OK);
  ASSERT_EQ(rxed_handles, 1u);

  // Things went well!  Cancel our on_failure cleanup routine and Stash our
  // control channel endpoint, we will close it when it is time for our
  // external thread and process to terminate.
  control_channel_ = std::move(local);
  on_failure.cancel();
}

void ExternalThread::Stop() {
  external_thread_.reset();
  control_channel_.reset();
}
