// Copyright 2017 The Abseil Authors.
//
// 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
//
//      https://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 "absl/base/call_once.h"

#include <thread>
#include <vector>

#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"

namespace absl {
inline namespace lts_2019_08_08 {
namespace {

absl::once_flag once;

ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);

int running_thread_count GUARDED_BY(counters_mu) = 0;
int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
int call_once_finished_count GUARDED_BY(counters_mu) = 0;
int call_once_return_count GUARDED_BY(counters_mu) = 0;
bool done_blocking GUARDED_BY(counters_mu) = false;

// Function to be called from absl::call_once.  Waits for a notification.
void WaitAndIncrement() {
  counters_mu.Lock();
  ++call_once_invoke_count;
  counters_mu.Unlock();

  counters_mu.LockWhen(Condition(&done_blocking));
  ++call_once_finished_count;
  counters_mu.Unlock();
}

void ThreadBody() {
  counters_mu.Lock();
  ++running_thread_count;
  counters_mu.Unlock();

  absl::call_once(once, WaitAndIncrement);

  counters_mu.Lock();
  ++call_once_return_count;
  counters_mu.Unlock();
}

// Returns true if all threads are set up for the test.
bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
  // All ten threads must be running, and WaitAndIncrement should be blocked.
  return running_thread_count == 10 && call_once_invoke_count == 1;
}

TEST(CallOnceTest, ExecutionCount) {
  std::vector<std::thread> threads;

  // Start 10 threads all calling call_once on the same once_flag.
  for (int i = 0; i < 10; ++i) {
    threads.emplace_back(ThreadBody);
  }


  // Wait until all ten threads have started, and WaitAndIncrement has been
  // invoked.
  counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));

  // WaitAndIncrement should have been invoked by exactly one call_once()
  // instance.  That thread should be blocking on a notification, and all other
  // call_once instances should be blocking as well.
  EXPECT_EQ(call_once_invoke_count, 1);
  EXPECT_EQ(call_once_finished_count, 0);
  EXPECT_EQ(call_once_return_count, 0);

  // Allow WaitAndIncrement to finish executing.  Once it does, the other
  // call_once waiters will be unblocked.
  done_blocking = true;
  counters_mu.Unlock();

  for (std::thread& thread : threads) {
    thread.join();
  }

  counters_mu.Lock();
  EXPECT_EQ(call_once_invoke_count, 1);
  EXPECT_EQ(call_once_finished_count, 1);
  EXPECT_EQ(call_once_return_count, 10);
  counters_mu.Unlock();
}

}  // namespace
}  // inline namespace lts_2019_08_08
}  // namespace absl
