carb/tasking/TaskingTypes.h
File members: carb/tasking/TaskingTypes.h
// Copyright (c) 2020-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.
//
#pragma once
#include "../Defines.h"
namespace carb
{
namespace tasking
{
class Counter DOXYGEN_EMPTY_CLASS;
class Mutex DOXYGEN_EMPTY_CLASS;
class Semaphore DOXYGEN_EMPTY_CLASS;
class SharedMutex DOXYGEN_EMPTY_CLASS;
class ConditionVariable DOXYGEN_EMPTY_CLASS;
struct ITasking;
constexpr uint64_t kInfinite = uint64_t(-1);
enum class Priority
{
eLow,
eMedium,
eHigh,
eMain,
eCount,
// Aliases
eDefault = eMedium,
};
enum class ObjectType
{
eNone,
eCounter,
eTaskContext,
ePtrTaskContext,
eTaskGroup,
eSharedState,
eFutex1,
eFutex2,
eFutex4,
eFutex8,
eTrackerGroup,
eTaskName,
eTaskNameLiteral,
};
using OnTaskFn = void (*)(void* taskArg);
using ApplyFn = void (*)(size_t index, void* taskArg);
using ApplyBatchFn = void (*)(size_t startIndex, size_t endIndex, void* taskArg);
using TaskStorageDestructorFn = void (*)(void* arg);
using TaskStorageKey = size_t;
constexpr TaskStorageKey kInvalidTaskStorageKey = size_t(-1);
using TaskContext = size_t;
constexpr TaskContext kInvalidTaskContext = 0;
constexpr uint32_t kMaxFibers = 1048575;
struct Object
{
ObjectType type;
void* data;
};
struct TaskDesc
{
size_t size{ sizeof(TaskDesc) };
OnTaskFn task;
void* taskArg;
Priority priority;
Object requiredObject;
Semaphore* waitSemaphore;
OnTaskFn cancel;
// Internal only
Object const* trackers{ nullptr };
size_t numTrackers{ 0 };
constexpr TaskDesc(OnTaskFn task_ = nullptr,
void* taskArg_ = nullptr,
Priority priority_ = Priority::eLow,
Counter* requiredCounter_ = nullptr,
Semaphore* waitSemaphore_ = nullptr,
OnTaskFn cancel_ = nullptr)
: task(task_),
taskArg(taskArg_),
priority(priority_),
requiredObject{ ObjectType::eCounter, requiredCounter_ },
waitSemaphore(waitSemaphore_),
cancel(cancel_)
{
}
};
struct TaskingDesc
{
uint32_t fiberCount;
uint32_t threadCount;
uint32_t* threadAffinity;
uint64_t stackSize;
};
enum class TaskDebugState
{
Pending,
New,
Running,
Waiting,
Finished,
};
struct TaskDebugInfo
{
size_t sizeOf{ sizeof(TaskDebugInfo) };
TaskContext context{};
TaskDebugState state{};
OnTaskFn task{};
void* taskArg{};
size_t numCreationFrames{ 0 };
void** creationCallstack{ nullptr };
size_t numWaitingFrames{ 0 };
void** waitingCallstack{ nullptr };
size_t taskNameSize{ 0 };
char* taskName{ nullptr };
};
using TaskDebugInfoFn = bool (*)(const TaskDebugInfo& info, void* context);
#ifndef DOXYGEN_BUILD
namespace detail
{
template <class T>
struct GenerateFuture;
template <class T>
class SharedState;
} // namespace detail
struct Trackers;
struct RequiredObject;
template <class T>
class Promise;
template <class T>
class SharedFuture;
#endif
template <class T = void>
class Future
{
public:
constexpr Future() noexcept = default;
~Future();
Future(Future&& rhs) noexcept;
Future& operator=(Future&& rhs) noexcept;
bool valid() const noexcept;
bool try_wait() const;
void wait() const;
template <class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& dur) const;
template <class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& when) const;
T get();
bool isCanceled() const;
SharedFuture<T> share();
const TaskContext* task_if() const;
operator RequiredObject() const;
template <class Callable, class... Args>
auto then(Priority prio, Trackers&& trackers, Callable&& f, Args&&... args);
private:
template <class U>
friend struct detail::GenerateFuture;
template <class U>
friend class Promise;
template <class U>
friend class SharedFuture;
CARB_PREVENT_COPY(Future);
constexpr Future(detail::SharedState<T>* state) noexcept;
Future(TaskContext task, detail::SharedState<T>* state) noexcept;
detail::SharedState<T>* m_state{ nullptr };
};
#ifndef DOXYGEN_BUILD
template <>
class Future<void>
{
public:
constexpr Future() noexcept = default;
~Future();
Future(Future&& rhs) noexcept;
Future& operator=(Future&& rhs) noexcept;
bool valid() const noexcept;
bool try_wait() const;
void wait() const;
template <class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& dur) const;
template <class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& when) const;
void get();
SharedFuture<void> share();
const TaskContext* task_if() const;
operator RequiredObject() const;
template <class Callable, class... Args>
auto then(Priority prio, Trackers&& trackers, Callable&& f, Args&&... args);
private:
template <class U>
friend struct detail::GenerateFuture;
template <class U>
friend class Future;
template <class U>
friend class Promise;
template <class U>
friend class SharedFuture;
friend struct Tracker;
TaskContext* ptask();
detail::SharedState<void>* state() const noexcept;
Future(TaskContext task);
Future(detail::SharedState<void>* state);
Object m_obj{ ObjectType::eNone, nullptr };
};
#endif
template <class T = void>
class SharedFuture
{
public:
SharedFuture() noexcept = default;
SharedFuture(const SharedFuture<T>& other) noexcept;
SharedFuture(SharedFuture<T>&& other) noexcept;
SharedFuture(Future<T>&& fut) noexcept;
~SharedFuture();
SharedFuture<T>& operator=(const SharedFuture<T>& other);
SharedFuture<T>& operator=(SharedFuture<T>&& other) noexcept;
const T& get() const;
bool valid() const noexcept;
bool try_wait() const;
void wait() const;
template <class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& dur) const;
template <class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& when) const;
bool isCanceled() const;
operator RequiredObject() const;
const TaskContext* task_if() const;
template <class Callable, class... Args>
auto then(Priority prio, Trackers&& trackers, Callable&& f, Args&&... args);
private:
detail::SharedState<T>* m_state{ nullptr };
};
#ifndef DOXYGEN_BUILD
template <class T>
class SharedFuture<T&>
{
public:
constexpr SharedFuture() noexcept = default;
SharedFuture(const SharedFuture& other) noexcept;
SharedFuture(SharedFuture&& other) noexcept;
SharedFuture(Future<T&>&& fut) noexcept;
~SharedFuture();
SharedFuture& operator=(const SharedFuture& other);
SharedFuture& operator=(SharedFuture&& other) noexcept;
T& get() const;
bool valid() const noexcept;
bool try_wait() const;
void wait() const;
template <class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& dur) const;
template <class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& when) const;
bool isCanceled() const;
operator RequiredObject() const;
const TaskContext* task_if() const;
template <class Callable, class... Args>
auto then(Priority prio, Trackers&& trackers, Callable&& f, Args&&... args);
private:
detail::SharedState<T&>* m_state{ nullptr };
};
template <>
class SharedFuture<void>
{
public:
constexpr SharedFuture() noexcept = default;
SharedFuture(const SharedFuture<void>& other) noexcept;
SharedFuture(SharedFuture<void>&& other) noexcept;
SharedFuture(Future<void>&& fut) noexcept;
~SharedFuture();
SharedFuture<void>& operator=(const SharedFuture<void>& other);
SharedFuture<void>& operator=(SharedFuture<void>&& other) noexcept;
void get() const;
bool valid() const noexcept;
bool try_wait() const;
void wait() const;
template <class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& dur) const;
template <class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& when) const;
operator RequiredObject() const;
const TaskContext* task_if() const;
template <class Callable, class... Args>
auto then(Priority prio, Trackers&& trackers, Callable&& f, Args&&... args);
private:
friend struct Tracker;
TaskContext* ptask();
detail::SharedState<void>* state() const;
Object m_obj{ ObjectType::eNone, nullptr };
};
#endif
template <class T = void>
class Promise
{
CARB_PREVENT_COPY(Promise);
public:
Promise();
Promise(Promise&& other) noexcept;
~Promise();
Promise& operator=(Promise&& other) noexcept;
void swap(Promise& other) noexcept;
Future<T> get_future();
void set_value(const T& value);
void set_value(T&& value);
void setCanceled();
private:
using State = detail::SharedState<T>;
State* m_state{ nullptr };
};
#ifndef DOXYGEN_BUILD
template <class T>
class Promise<T&>
{
CARB_PREVENT_COPY(Promise);
public:
Promise();
Promise(Promise&& other) noexcept;
~Promise();
Promise& operator=(Promise&& other) noexcept;
void swap(Promise& other) noexcept;
Future<T&> get_future();
void set_value(T& value);
void setCanceled();
private:
using State = detail::SharedState<T&>;
State* m_state{ nullptr };
};
template <>
class Promise<void>
{
CARB_PREVENT_COPY(Promise);
public:
Promise();
Promise(Promise&& other) noexcept;
~Promise();
Promise& operator=(Promise&& other) noexcept;
void swap(Promise& other) noexcept;
Future<void> get_future();
void set_value();
private:
using State = detail::SharedState<void>;
State* m_state{ nullptr };
};
#endif
} // namespace tasking
} // namespace carb