// Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

//! @file TbbSchedulerState.h
//!
//! @brief Defines @ref omni::kit::exec::core::unstable::TbbSchedulerState.
#pragma once

#include <tbb/concurrent_queue.h>
#include <tbb/enumerable_thread_specific.h>
#include <tbb/recursive_mutex.h>
#include <tbb/task.h>

#include <atomic>
#include <thread>

namespace omni
{
namespace kit
{
namespace exec
{
namespace core
{
namespace unstable
{

//! Implementation details for the TBB based task scheduler state singleton.
//!
//! Will be replaced.
struct TbbSchedulerState
{
    tbb::concurrent_queue<tbb::task*> queueParallel; //!< Queue of parallel tasks. Allows concurrent insertion.
    tbb::concurrent_queue<tbb::task*> queueSerial; //!< Queue of serial tasks. Allows concurrent insertion.
    tbb::concurrent_queue<tbb::task*> queueIsolate; //!< Queue of isolate tasks. Allows concurrent insertion.

    std::atomic<int> totalTasksInFlight{ 0 }; //!< Track total number of serial and parallel tasks. Used for isolation.
    tbb::enumerable_thread_specific<int> tasksExecutingPerThread{ 0 }; //!< Track execution per thread to know if
                                                                       //!< waiting on a task contributed to a total
                                                                       //!< tasks in flight.

    std::atomic<std::thread::id> serialThreadId; //!< Thread currently processing serial tasks.
    std::atomic<std::thread::id> isolateThreadId; //!< Thread currently processing isolate tasks.

    tbb::recursive_mutex executingThreadMutex; //!< Mutex used to serialize the processing of all context threads
                                               //!< (i.e., all threads which kickstarted execution from a any
                                               //!< given ExecutionContexts). This ensures that up to a single context
                                               //!< thread is computing at any given moment, regardless of the number
                                               //!< of threads that kickstarted execution from a given context OR the
                                               //!< number of different ExecutionContexts that began executing
                                               //!< concurrently (assuming that the user is utilizing the provided
                                               //!< ParallelScheduler for those contexts, otherwise they will need to
                                               //!< manage the synchronization on their own), which is important because
                                               //!< serial and isolate tasks are scheduled to run on a context thread,
                                               //!< so allowing multiple context threads to evaluate concurrently would
                                               //!< break the promise that serial and isolate tasks cannot be executed
                                               //!< in multiple threads simultaneously.
};

} // namespace unstable
} // namespace core
} // namespace exec
} // namespace kit
} // namespace omni
