// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed 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 "starboard/thread.h"

#include <process.h>
#include <pthread.h>

#include <memory>

#include "starboard/common/log.h"
#include "starboard/common/once.h"
#include "starboard/shared/win32/error_utils.h"
#include "starboard/shared/win32/thread_private.h"
#include "starboard/shared/win32/wchar_utils.h"

namespace sbwin32 = starboard::shared::win32;

using sbwin32::DebugLogWinError;
using sbwin32::GetThreadSubsystemSingleton;
using sbwin32::SbThreadPrivate;
using sbwin32::ThreadCreateInfo;
using sbwin32::ThreadGetLocalValue;
using sbwin32::ThreadSetLocalValue;
using sbwin32::ThreadSubsystemSingleton;
using sbwin32::wchar_tToUTF8;

void ResetWinError() {
  SetLastError(0);
}

int RunThreadLocalDestructors(ThreadSubsystemSingleton* singleton) {
  int num_destructors_called = 0;

  for (auto it = singleton->thread_local_keys_.begin();
       it != singleton->thread_local_keys_.end();) {
    auto curr_it = it++;

    if (!curr_it->second->destructor) {
      continue;
    }
    auto key = curr_it->second;
    void* entry = ThreadGetLocalValue(reinterpret_cast<SbThreadLocalKey>(key));
    if (!entry) {
      continue;
    }
    ThreadSetLocalValue(reinterpret_cast<SbThreadLocalKey>(key), nullptr);
    ++num_destructors_called;
    curr_it->second->destructor(entry);
  }
  return num_destructors_called;
}

int CountTlsObjectsRemaining(ThreadSubsystemSingleton* singleton) {
  int num_objects_remain = 0;
  for (auto it = singleton->thread_local_keys_.begin();
       it != singleton->thread_local_keys_.end(); ++it) {
    if (!it->second->destructor) {
      continue;
    }
    auto key = it->second;
    void* entry = ThreadGetLocalValue(reinterpret_cast<SbThreadLocalKey>(key));
    if (!entry) {
      continue;
    }
    ++num_objects_remain;
  }
  return num_objects_remain;
}

void CallThreadLocalDestructorsMultipleTimes() {
  // The number of passes conforms to the base_unittests. This is useful for
  // destructors that insert new objects into thread local storage. These
  // objects then need to be destroyed as well in subsequent passes. The total
  // number of passes is 4, which is one more than what base_unittest tests
  // for.
  const int kNumDestructorPasses = 4;

  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
  int num_tls_objects_remaining = 0;
  // TODO note that the implementation below holds a global lock
  // while processing TLS destructors on thread exit. This could
  // be a bottleneck in some scenarios. A lockless approach may be preferable.
  pthread_mutex_lock(&singleton->mutex_);

  for (int i = 0; i < kNumDestructorPasses; ++i) {
    // Run through each destructor and call it.
    const int num_destructors_called = RunThreadLocalDestructors(singleton);
    if (0 == num_destructors_called) {
      break;  // No more destructors to call.
    }
  }
  num_tls_objects_remaining = CountTlsObjectsRemaining(singleton);
  pthread_mutex_unlock(&singleton->mutex_);

  SB_DCHECK(num_tls_objects_remaining == 0) << "Dangling objects in TLS exist.";
}

namespace {

unsigned ThreadTrampoline(void* thread_create_info_context) {
  std::unique_ptr<ThreadCreateInfo> info(
      static_cast<ThreadCreateInfo*>(thread_create_info_context));

  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
  ThreadSetLocalValue(singleton->thread_private_key_, &info->thread_private_);
  pthread_setname_np(pthread_self(), info->name_.c_str());

  void* result = info->entry_point_(info->user_context_);

  CallThreadLocalDestructorsMultipleTimes();

  pthread_mutex_lock(&info->thread_private_.mutex_);
  info->thread_private_.result_ = result;
  info->thread_private_.result_is_valid_ = true;
  pthread_cond_signal(&info->thread_private_.condition_);
  while (info->thread_private_.wait_for_join_) {
    pthread_cond_wait(&info->thread_private_.condition_,
                      &info->thread_private_.mutex_);
  }
  pthread_mutex_destroy(&info->thread_private_.mutex_);

  return 0;
}

int SbThreadPriorityToWin32Priority(SbThreadPriority priority) {
  switch (priority) {
    case kSbThreadPriorityLowest:
      return THREAD_PRIORITY_LOWEST;
    case kSbThreadPriorityLow:
      return THREAD_PRIORITY_BELOW_NORMAL;
    case kSbThreadPriorityNormal:
    case kSbThreadNoPriority:
      return THREAD_PRIORITY_NORMAL;
    case kSbThreadPriorityHigh:
      return THREAD_PRIORITY_ABOVE_NORMAL;
    case kSbThreadPriorityHighest:
      return THREAD_PRIORITY_HIGHEST;
    case kSbThreadPriorityRealTime:
      return THREAD_PRIORITY_TIME_CRITICAL;
  }
  SB_NOTREACHED() << "Invalid priority " << priority;
  return 0;
}

SbThreadPriority Win32PriorityToSbThreadPriority(int priority) {
  switch (priority) {
    case THREAD_PRIORITY_LOWEST:
      return kSbThreadPriorityLowest;
    case THREAD_PRIORITY_BELOW_NORMAL:
      return kSbThreadPriorityLow;
    case THREAD_PRIORITY_NORMAL:
      return kSbThreadPriorityNormal;
    case THREAD_PRIORITY_ABOVE_NORMAL:
      return kSbThreadPriorityHigh;
    case THREAD_PRIORITY_HIGHEST:
      return kSbThreadPriorityHighest;
    case THREAD_PRIORITY_TIME_CRITICAL:
      return kSbThreadPriorityRealTime;
  }
  SB_NOTREACHED() << "Invalid priority " << priority;
  return kSbThreadPriorityNormal;
}
}  // namespace

#if SB_API_VERSION < 16
// Note that SetThreadAffinityMask() is not available on some
// platforms (eg UWP). If it's necessary for a non-UWP platform,
// please fork this implementation for UWP.
SbThread SbThreadCreate(int64_t stack_size,
                        SbThreadPriority priority,
                        SbThreadAffinity affinity,
                        bool joinable,
                        const char* name,
                        SbThreadEntryPoint entry_point,
                        void* context) {
  if (entry_point == NULL) {
    return kSbThreadInvalid;
  }
  ThreadCreateInfo* info = new ThreadCreateInfo();

  info->entry_point_ = entry_point;
  info->user_context_ = context;
  info->thread_private_.wait_for_join_ = joinable;
  if (name) {
    info->name_ = name;
  }

  // Create the thread suspended, and then resume once ThreadCreateInfo::handle_
  // has been set, so that it's always valid in the ThreadCreateInfo
  // destructor.
  uintptr_t handle =
      _beginthreadex(NULL, static_cast<unsigned int>(stack_size),
                     ThreadTrampoline, info, CREATE_SUSPENDED, NULL);
  SB_DCHECK(handle);
  info->thread_private_.handle_ = reinterpret_cast<HANDLE>(handle);
  ResetWinError();
  if (priority != kSbThreadNoPriority &&
      !SetThreadPriority(info->thread_private_.handle_,
                         SbThreadPriorityToWin32Priority(priority)) &&
      !GetLastError()) {
    SB_LOG(ERROR) << "Failed to set priority for thread " << (name ? name : "")
                  << " to " << priority;
    DebugLogWinError();
  }

  ResumeThread(info->thread_private_.handle_);

  return &info->thread_private_;
}
#endif  // SB_API_VERSION < 16

bool SbThreadSetPriority(SbThreadPriority priority) {
  return SetThreadPriority(GetCurrentThread(),
                           SbThreadPriorityToWin32Priority(priority));
}

bool SbThreadGetPriority(SbThreadPriority* priority) {
  int res = GetThreadPriority(GetCurrentThread());
  *priority = Win32PriorityToSbThreadPriority(res);
  return true;
}
