AIStatefulTask ‐ Asynchronous, Stateful Task Scheduler library.

Threads-like task objects evolving through user-defined states.

AIStatefulTask.h
Go to the documentation of this file.
1
41#ifndef AISTATEFULTASK_H
42#define AISTATEFULTASK_H
43
44#include "threadpool/Timer.h"
45#include "threadsafe/aithreadsafe.h"
46#include "threadsafe/AIMutex.h"
47#include "threadpool/AIQueueHandle.h"
48#include "utils/AIRefCount.h"
49#include "utils/macros.h"
50#include "utils/FuzzyBool.h"
51#include "utils/is_power_of_two.h"
52#include "debug.h"
53#include <list>
54#include <chrono>
55#include <functional>
56#include <tuple>
57#ifdef TRACY_FIBERS
58#include <Tracy.hpp>
59#include <cstring>
60#include <cstdlib>
61#endif
62
63class AIEngine;
66
68using AIWaitConditionFunc = std::function<bool()>;
69
95class AIStatefulTask : public AIRefCount
96{
97 public:
98 using state_type = uint32_t;
99 using condition_type = uint32_t;
100 // The two most significant bits are reserved for flow control.
101 static constexpr condition_type slow_down_condition = 0x40000000; // This task was running when the thread pool ran full.
102 static constexpr condition_type thread_pool_full_condition = 0x80000000; // This task couldn't be added to the thread pool queue because that was full.
103 static constexpr condition_type AND_conditions_mask = 0xf0000000;
104 static constexpr condition_type OR_conditions_mask = 0x0fffffff;
105
107 {
108 boost::intrusive_ptr<AIStatefulTask> task;
109 condition_type condition;
110
111 void signal() const { task->signal(condition); }
112 };
113
114 private:
116 enum event_type {
117 initial_run,
118 schedule_run,
119 normal_run,
120 insert_abort
121 };
122
123 protected:
132 bs_killed
133 };
134
135 public:
137 static constexpr state_type state_end = bs_killed + 1;
143 };
144
163 struct Handler
164 {
166 enum type_t {
171 };
176 };
178 union Handle {
180 AIQueueHandle queue_handle;
181
183 Handle() { }
185 Handle(AIEngine* engine_) : engine(engine_) { }
187 Handle(AIQueueHandle queue_handle_) : queue_handle(queue_handle_) { }
188 };
191
193 Handler(special_t special) : m_type((type_t)special) { }
195 Handler(AIEngine* engine) : m_handle(engine), m_type(engine_h) { ASSERT(engine); }
197 Handler(AIQueueHandle queue_handle) : m_handle(queue_handle), m_type(thread_pool_h) { }
199 bool is_engine() const { return m_type == engine_h; }
201 bool is_immediate() const { return m_type == immediate_h; }
203 bool is_thread_pool() const { return m_type == thread_pool_h; }
205 AIQueueHandle get_queue_handle() const { return m_type == thread_pool_h ? m_handle.queue_handle : AIQueueHandle((std::size_t)0); }
207 explicit operator bool() const { return m_type != idle_h; } // Return true when this handler can be used to actually run in.
208
209 // Gcc complains because what is defined depends on the value of m_type.
210 PRAGMA_DIAGNOSTIC_PUSH_IGNORE_maybe_uninitialized
212 bool operator==(Handler handler) const {
213 return m_type == handler.m_type &&
214 (m_type != engine_h || m_handle.engine == handler.m_handle.engine) &&
216 PRAGMA_DIAGNOSTIC_POP
217 bool operator!=(Handler handler) const { return !operator==(handler); }
218
219 friend std::ostream& operator<<(std::ostream& os, Handler const& handler);
220 };
221
223 {
224 AIStatefulTask const* m_task;
225 condition_type m_conditions;
226 Conditions(AIStatefulTask const* task, condition_type conditions) : m_task(task), m_conditions(conditions) { }
227
228 void print_on(std::ostream& os) const;
229
230 friend std::ostream& operator<<(std::ostream& os, Conditions conditions)
231 {
232 os << std::hex << conditions.m_conditions << std::dec << " (";
233 if (AI_LIKELY(utils::is_power_of_two(conditions.m_conditions)))
234 return os << conditions.m_task->condition_str_impl(conditions.m_conditions) << ')';
235 conditions.print_on(os);
236 return os << ')';
237 }
238 };
239
240 // Also needs access to condition_str_impl.
241 friend std::ostream& operator<<(std::ostream&, Conditions);
242
243 Conditions print_conditions(condition_type conditions)
244 {
245 return { this, conditions };
246 }
247
248 protected:
249#ifndef DOXYGEN
250 struct multiplex_state_st {
251 base_state_type base_state;
252 Handler current_handler; // Current handler.
253 AIWaitConditionFunc wait_condition;
254 condition_type conditions;
255 multiplex_state_st() : base_state(bs_reset), current_handler(Handler::idle), wait_condition(nullptr) { }
256 };
257
258 struct sub_state_st {
259 condition_type skip_wait;
261 condition_type idle;
262 state_type run_state;
263 bool reset;
264 bool need_run;
265 bool aborted;
266 bool finished;
267#if CW_DEBUG
268 bool wait_called;
269#endif
270 };
271
272 private:
273 // Base state.
274 using multiplex_state_type = aithreadsafe::Wrapper<multiplex_state_st, aithreadsafe::policy::Primitive<std::mutex>>;
275 multiplex_state_type mState;
276
277 protected:
278 // Sub state.
279 using sub_state_type = aithreadsafe::Wrapper<sub_state_st, aithreadsafe::policy::Primitive<std::mutex>>;
280 sub_state_type mSubState;
281#endif // DOXYGEN
282
283 private:
284 // Mutex protecting everything below and making sure only one thread runs the task at a time.
285 AIMutex mMultiplexMutex;
286 // Mutex that is locked while calling *_impl() functions and the call back.
287 std::recursive_mutex mRunMutex;
288
289 using clock_type = std::chrono::steady_clock;
290 using duration_type = clock_type::duration;
291
292 clock_type::rep mSleep;
293
294 // Callback facilities.
295 // From within an other stateful task:
296 boost::intrusive_ptr<AIStatefulTask> mParent; // The parent object that started this task, or nullptr if there isn't any.
297 condition_type mParentCondition; // The condition (bit) that the parent should be signaled with upon a successful finish.
298 on_abort_st mOnAbort; // What to do with the parent (if any) when aborted.
299 // From outside a stateful task:
300 std::function<void (bool)> mCallback; // Pointer to signal/connection, or nullptr when not connected.
301
302 // Engine stuff.
303 Handler mDefaultHandler; // Default engine or queue.
304 Handler mTargetHandler; // Requested engine by a call to yield.
305 bool mYield; // True when any yield function was called, except for yield_if_not when the passed engine already matched.
306
307#if CW_DEBUG
308 // Debug stuff.
309 std::thread::id mThreadId; // The thread currently running multiplex() (or std::thread::id() when none).
310 base_state_type mDebugLastState; // The previous state that multiplex() had a normal run with.
311 bool mDebugShouldRun; // Set if we found evidence that we should indeed call multiplex_impl().
312 bool mDebugAborted; // True when abort() was called.
313 bool mDebugSignalPending; // True while wait() was called but didn't get idle because of a pending call to signal() that wasn't handled yet.
314 bool mDebugSetStatePending; // True while set_state() was called by not handled yet.
315 bool mDebugRefCalled; // True when ref() is called (or will be called within the critial area of mMultiplexMutex).
316#endif
317
318 static thread_local AIStatefulTask* tl_parent_task;
319
320#if defined(CWDEBUG) && !defined(DOXYGEN)
321 protected:
322 bool mSMDebug; // Print debug output only when true (SM = 'State Machine', the name of this class before it was renamed to StatefulTask).
323#endif
324#if CW_DEBUG && !defined(DOXYGEN)
325 public:
326 bool m_may_not_be_deleted;
327#endif
328
329 private:
330 duration_type mDuration; // Total time spent running in the main thread.
331
332#ifdef TRACY_FIBERS
333 protected:
334 char const* m_tracy_fiber_name; // Set by call to set_tracy_fiber_name. Normally equal to the return value of task_name_impl()
335 // called directly after creation (i.e. create or create_from_tuple).
336 // Made protected to allow a derived class to change the name dynamically: this should happen
337 // from multiplex_impl only (otherwise it is not thread-safe) and will change the name for
338 // the *next* invocation of multiplex(). The actual fiber is determined by the value of the
339 // pointer, not the string that it points to.
340 static thread_local char const* s_tl_tracy_fiber_name; // Set to m_tracy_fiber_name when entering multiplex().
341#endif
342
343 public:
352 AIStatefulTask(CWDEBUG_ONLY(bool debug)) : mDefaultHandler(Handler::idle), mTargetHandler(Handler::idle), mYield(false),
353#if CW_DEBUG
354 mDebugLastState(bs_killed), mDebugShouldRun(false), mDebugAborted(false), mDebugSignalPending(false),
355 mDebugSetStatePending(false), mDebugRefCalled(false),
356#endif
357#ifdef CWDEBUG
358 mSMDebug(debug),
359#endif
360#if CW_DEBUG
361 m_may_not_be_deleted(false),
362#endif
363 mDuration(duration_type::zero())
364#ifdef TRACY_FIBERS
365 , m_tracy_fiber_name(nullptr)
366#endif
367 { }
368
369#ifdef TRACY_FIBERS
370 void set_tracy_fiber_name(char const* tracy_fiber_name);
371#endif
372
373 protected:
376 {
377#if CW_DEBUG
378 base_state_type state = multiplex_state_type::rat(mState)->base_state;
379 ASSERT(state == bs_killed || state == bs_reset);
380 ASSERT(!m_may_not_be_deleted);
381#endif
382 }
383
384 public:
402 void run(Handler default_handler, std::function<void (bool)> cb_function);
403
405 void run(std::function<void (bool)> cb_function) { run(Handler::immediate, cb_function); }
406
418 void run(Handler default_handler, AIStatefulTask* parent, condition_type condition, on_abort_st on_abort = abort_parent);
419
423 void run(AIStatefulTask* parent, condition_type condition, on_abort_st on_abort = abort_parent) { run(Handler::immediate, parent, condition, on_abort); }
424
430 void run(Handler default_handler = Handler::immediate) { run(default_handler, nullptr, 0, do_nothing); }
431
433
444 void kill();
446
447 protected:
471 void set_state(state_type new_state); // Run this state the NEXT loop.
472
489 void wait(condition_type conditions);
490
500 void wait_until(AIWaitConditionFunc const& wait_condition, condition_type conditions);
501
512 void wait_until(AIWaitConditionFunc const& wait_condition, condition_type conditions, state_type new_state)
513 {
514 set_state(new_state);
515 wait_until(wait_condition, conditions);
516 }
517
519
528 void finish();
529
535 inline utils::FuzzyBool is_self_locked(AIStatefulTaskMutex const& stateful_task_mutex, AIStatefulTaskMutexNode const* handle);
536
564 void yield();
565
574 void target(Handler handler);
575
581 void yield(Handler handler);
582
593 void yield_frame(AIEngine* engine, unsigned int frames);
594
603 void yield_ms(AIEngine* engine, unsigned int ms);
604
611 bool yield_if_not(Handler handler);
612
615
616 // Calls wait_until.
617 friend class AIFriendOfStatefulTask;
618
619 public:
635 void abort();
636
650 bool signal(condition_type condition);
651
653
654 public:
655 // Accessors.
656
665 bool running() const { return multiplex_state_type::crat(mState)->base_state == bs_multiplex; }
666
674 bool waiting() const;
675
686 bool waiting_or_aborting() const;
687
694 bool active(Handler handler) const { return multiplex_state_type::crat(mState)->current_handler == handler; }
695
702 bool is_immediate() const { return multiplex_state_type::crat(mState)->current_handler.is_immediate(); }
703
705 // For debugging purposes mainly.
706 bool default_is_immediate() const { return mDefaultHandler.is_immediate(); }
708
716 bool finished() const
717 {
718 sub_state_type::crat sub_state_r(mSubState);
719 return sub_state_r->finished ? &AIStatefulTask::mOnAbort : 0;
720 }
721
727 bool aborted() const { return sub_state_type::crat(mSubState)->aborted; }
728
732 bool executing() const { return mMultiplexMutex.is_self_locked(); }
733
739 static char const* state_str(base_state_type state);
740#ifdef CWDEBUG
746 static char const* event_str(event_type event);
747#endif
748
754 duration_type getDuration() const { return mDuration; }
755
759 char const* task_name() const { return task_name_impl(); }
760
761 protected:
768 virtual char const* condition_str_impl(condition_type condition) const;
770 virtual char const* state_str_impl(state_type run_state) const;
773 virtual char const* task_name_impl() const = 0;
775 virtual void initialize_impl();
777 virtual void multiplex_impl(state_type run_state) = 0;
779 virtual void abort_impl();
781 virtual void finish_impl();
783 virtual void force_killed();
785
786 private:
787 void reset(); // Called from run() to (re)initialize a (re)start.
788
794 void multiplex(event_type event, Handler handler = Handler::idle);
795
796 void insert_multiplex(event_type event, Handler handler = Handler::idle)
797 {
798#ifdef TRACY_FIBERS
799 char const* parent_tracy_fiber_name = s_tl_tracy_fiber_name;
800 if (AI_UNLIKELY(parent_tracy_fiber_name))
801 {
802 //Dout(dc::notice, "Calling TracyFiberLeave()");
803 TracyFiberLeave;
804 s_tl_tracy_fiber_name = nullptr;
805 }
806#endif
807 multiplex(event, handler);
808#ifdef TRACY_FIBERS
809 if (AI_UNLIKELY(parent_tracy_fiber_name))
810 {
811 s_tl_tracy_fiber_name = parent_tracy_fiber_name;
812 //Dout(dc::notice, "Calling TracyFiberEnter(\"" << parent_tracy_fiber_name << "\")");
813 TracyFiberEnter(parent_tracy_fiber_name);
814 }
815#endif
816 }
817
818 state_type begin_loop(); // Called from multiplex() at the start of a loop.
819 void callback(); // Called when the task finished.
820 // Count frames if necessary and return true when the task is still sleeping.
821 // Sleeping in milliseconds (as opposed to counting frames) is assumed to only be done in order
822 // to give other tasks cpu. Therefore, if 'only_task' is set and this sleep is not counting
823 // frames, then stop sleeping.
824 bool sleep(clock_type::time_point current_time, bool only_task)
825 {
826 if (mSleep == 0)
827 return false;
828 else if (mSleep < 0)
829 ++mSleep;
830 else if (mSleep <= current_time.time_since_epoch().count() || only_task)
831 mSleep = 0;
832 return mSleep != 0;
833 }
834
835 void add(duration_type delta) { mDuration += delta; }
836
837 void add_task_to_thread_pool(AIQueueHandle queue_handle, uint8_t const failure_count = 0); // Attempt to add this task to a theadpool queue.
838 void wait_AND(condition_type required); // Stop running until all `required` bits have been signaled (plus at least one of any other wait() condition).
839
840 friend class AIEngine; // Calls multiplex(), force_killed() and add().
841};
842
843namespace task {
844
845template<typename Type>
846concept TaskType = std::is_base_of_v<AIStatefulTask, Type>;
847
848} // namespace task
849
850#if defined(CWDEBUG) && !defined(DOXYGEN)
851NAMESPACE_DEBUG_CHANNELS_START
852extern channel_ct statefultask;
853NAMESPACE_DEBUG_CHANNELS_END
854#endif
855
857namespace statefultask {
858
893template<task::TaskType TaskType, typename... ARGS>
894boost::intrusive_ptr<TaskType> create(ARGS&&... args)
895{
896 DoutEntering(dc::statefultask, "statefultask::create<" << ::NAMESPACE_DEBUG::type_name_of<TaskType>() <<
897 ((LibcwDoutStream << ... << (std::string(", ") + ::NAMESPACE_DEBUG::type_name_of<ARGS>())), ">(") << join(", ", args...) << ')');
898 TaskType* task = new TaskType(std::forward<ARGS>(args)...);
899 AllocTag2(task, "Created with statefultask::create");
900#ifdef TRACY_FIBERS
901 task->set_tracy_fiber_name(task->task_name());
902#endif
903#ifdef CWDEBUG
904 Dout(dc::statefultask|continued_cf, "Returning task pointer " << (void*)task);
905 if ((void*)task != (void*)static_cast<AIStatefulTask*>(task))
906 Dout(dc::finish, " [" << static_cast<AIStatefulTask*>(task) << "].");
907 else
908 Dout(dc::finish, ".");
909#endif
910 return task;
911}
912
913template<task::TaskType TaskType, typename... ARGS>
914boost::intrusive_ptr<TaskType> create_from_tuple(std::tuple<ARGS...>&& args)
915{
916 DoutEntering(dc::statefultask, "statefultask::create_from_tuple<" << ::NAMESPACE_DEBUG::type_name_of<TaskType>() <<
917 ((LibcwDoutStream << ... << (std::string(", ") + ::NAMESPACE_DEBUG::type_name_of<ARGS>())), ">(") << args << ')');
918 TaskType* task = new TaskType(std::make_from_tuple<TaskType>(std::move(args)));
919 AllocTag2(task, "Created with statefultask::create_from_tuple");
920#ifdef TRACY_FIBERS
921 task->set_tracy_fiber_name(task->task_name());
922#endif
923#ifdef CWDEBUG
924 Dout(dc::statefultask|continued_cf, "Returning task pointer " << (void*)task);
925 if ((void*)task != (void*)static_cast<AIStatefulTask*>(task))
926 Dout(dc::finish, " [" << static_cast<AIStatefulTask*>(task) << "].");
927 else
928 Dout(dc::finish, '.');
929#endif
930 return task;
931}
932
933} // namespace statefultask
934
935#include "AIStatefulTaskMutex.h"
936#endif // AISTATEFULTASK_H
937
938#ifndef AISTATEFULTASK_H_definitions
939#define AISTATEFULTASK_H_definitions
940
941utils::FuzzyBool AIStatefulTask::is_self_locked(AIStatefulTaskMutex const& stateful_task_mutex, AIStatefulTaskMutexNode const* handle)
942{
943 return stateful_task_mutex.is_self_locked(handle);
944}
945
946#endif // AISTATEFULTASK_H_definitions
Mutex for stateful tasks. Declaration of class AIStatefulTaskMutex.
std::function< bool()> AIWaitConditionFunc
The type of the functor that must be passed as first parameter to AIStatefulTask::wait_until.
Definition: AIStatefulTask.h:68
Definition: AIEngine.h:110
Definition: AIFriendOfStatefulTask.h:61
Definition: AIStatefulTaskMutex.h:86
Definition: AIStatefulTask.h:96
duration_type getDuration() const
Definition: AIStatefulTask.h:754
bool running() const
Definition: AIStatefulTask.h:665
bool is_immediate() const
Definition: AIStatefulTask.h:702
on_abort_st
What to do when a child task is aborted.
Definition: AIStatefulTask.h:139
@ signal_parent
Call signal(condition_type) on the parent anyway.
Definition: AIStatefulTask.h:141
@ do_nothing
Abort without notifying the parent task.
Definition: AIStatefulTask.h:142
@ abort_parent
Call abort() on the parent.
Definition: AIStatefulTask.h:140
virtual char const * task_name_impl() const =0
This can be used to get a human readable name of the most-derived class. It must be guaranteed to alw...
virtual void force_killed()
Called from AIEngine::flush().
Definition: AIStatefulTask.cxx:1297
static char const * state_str(base_state_type state)
Definition: AIStatefulTask.cxx:1819
static constexpr state_type state_end
The next state value to use for derived classes.
Definition: AIStatefulTask.h:137
bool waiting() const
Definition: AIStatefulTask.cxx:484
bool aborted() const
Definition: AIStatefulTask.h:727
AIStatefulTask(bool debug)
Definition: AIStatefulTask.h:352
virtual void multiplex_impl(state_type run_state)=0
Called for base state bs_multiplex.
uint32_t state_type
The type of run_state.
Definition: AIStatefulTask.h:98
virtual void abort_impl()
Called for base state bs_abort.
Definition: AIStatefulTask.cxx:1287
char const * task_name() const
Definition: AIStatefulTask.h:759
bool active(Handler handler) const
Definition: AIStatefulTask.h:694
bool executing() const
Definition: AIStatefulTask.h:732
virtual void finish_impl()
Called for base state bs_finish.
Definition: AIStatefulTask.cxx:1292
bool finished() const
Definition: AIStatefulTask.h:716
uint32_t condition_type
The type of the skip_wait and idle bit masks.
Definition: AIStatefulTask.h:99
bool waiting_or_aborting() const
Definition: AIStatefulTask.cxx:490
virtual char const * state_str_impl(state_type run_state) const
Called to stringify a run state for debugging output. Must be overridden.
Definition: AIStatefulTask.cxx:1273
base_state_type
The type of mState.
Definition: AIStatefulTask.h:125
@ bs_killed
State after the call back, or when aborted before being initialized.
Definition: AIStatefulTask.h:132
@ bs_multiplex
State after initialize_impl and before finish() or abort().
Definition: AIStatefulTask.h:128
@ bs_abort
State after abort() and leaving inside multiplex_impl (if there), and before abort_impl().
Definition: AIStatefulTask.h:129
@ bs_initialize
State after run and before/during initialize_impl.
Definition: AIStatefulTask.h:127
@ bs_finish
State after finish() (assuming abort() isn't called) and leaving multiplex_impl (if there),...
Definition: AIStatefulTask.h:130
@ bs_callback
State after finish_impl() and before the call back.
Definition: AIStatefulTask.h:131
@ bs_reset
Idle state before run is called. Reference count is zero (except for a possible external boost::intru...
Definition: AIStatefulTask.h:126
virtual ~AIStatefulTask()
Destructor.
Definition: AIStatefulTask.h:375
virtual char const * condition_str_impl(condition_type condition) const
Called to stringify a condition type for debugging output.
Definition: AIStatefulTask.cxx:1264
virtual void initialize_impl()
Called for base state bs_initialize.
Definition: AIStatefulTask.cxx:1280
void set_state(state_type new_state)
Definition: AIStatefulTask.cxx:1354
utils::FuzzyBool is_self_locked(AIStatefulTaskMutex const &stateful_task_mutex, AIStatefulTaskMutexNode const *handle)
void finish()
Definition: AIStatefulTask.cxx:1725
void kill()
Definition: AIStatefulTask.cxx:1302
bool signal(condition_type condition)
Definition: AIStatefulTask.cxx:1643
void abort()
Definition: AIStatefulTask.cxx:1690
void run(AIStatefulTask *parent, condition_type condition, on_abort_st on_abort=abort_parent)
Definition: AIStatefulTask.h:423
void run(Handler default_handler=Handler::immediate)
Definition: AIStatefulTask.h:430
void run(std::function< void(bool)> cb_function)
The same as above but use the immediate Handler.
Definition: AIStatefulTask.h:405
void run(Handler default_handler, std::function< void(bool)> cb_function)
Definition: AIStatefulTask.cxx:1192
void wait_until(AIWaitConditionFunc const &wait_condition, condition_type conditions)
Definition: AIStatefulTask.cxx:1627
void wait_until(AIWaitConditionFunc const &wait_condition, condition_type conditions, state_type new_state)
Definition: AIStatefulTask.h:512
void wait(condition_type conditions)
Definition: AIStatefulTask.cxx:1507
void yield()
Definition: AIStatefulTask.cxx:1748
void yield_frame(AIEngine *engine, unsigned int frames)
Definition: AIStatefulTask.cxx:1800
void target(Handler handler)
Definition: AIStatefulTask.cxx:1764
bool yield_if_not(Handler handler)
Definition: AIStatefulTask.cxx:1790
void yield_ms(AIEngine *engine, unsigned int ms)
Definition: AIStatefulTask.cxx:1809
Tasks defined by the library project are put into this namespace.
Definition: AIStatefulTask.h:857
boost::intrusive_ptr< TaskType > create(ARGS &&... args)
Convenience function to create tasks.
Definition: AIStatefulTask.h:894
Definition: AIStatefulTaskMutex.h:42
Definition: AIStatefulTask.h:107
Definition: AIStatefulTask.h:223
Definition: AIStatefulTask.h:164
Handle m_handle
Extra data that depends on m_type.
Definition: AIStatefulTask.h:189
special_t
A typed use by the constuctor Handler(special_t).
Definition: AIStatefulTask.h:173
@ immediate
Construct an immediate Handler.
Definition: AIStatefulTask.h:175
@ idle
Construct an idle Handler.
Definition: AIStatefulTask.h:174
type_t
The type of m_type.
Definition: AIStatefulTask.h:166
@ engine_h
An engine Handler.
Definition: AIStatefulTask.h:169
@ immediate_h
An immediate Handler.
Definition: AIStatefulTask.h:168
@ idle_h
An idle Handler.
Definition: AIStatefulTask.h:167
@ thread_pool_h
A thread pool Handler.
Definition: AIStatefulTask.h:170
friend std::ostream & operator<<(std::ostream &os, Handler const &handler)
Write a Handler to an ostream.
Definition: AIStatefulTask.cxx:1118
bool operator==(Handler handler) const
Return true when equivalent to handler.
Definition: AIStatefulTask.h:212
Handler(AIQueueHandle queue_handle)
Construct a Handler from an AIQueueHandle.
Definition: AIStatefulTask.h:197
bool is_immediate() const
Return true if this is an immediate Handler.
Definition: AIStatefulTask.h:201
Handler(special_t special)
Construct a special Handler.
Definition: AIStatefulTask.h:193
bool is_thread_pool() const
Return true if this is a thread pool handler.
Definition: AIStatefulTask.h:203
Handler(AIEngine *engine)
Construct a Handler from an AIEngine pointer.
Definition: AIStatefulTask.h:195
AIQueueHandle get_queue_handle() const
Return the AIQueueHandle to use (only call when appropriate).
Definition: AIStatefulTask.h:205
type_t m_type
The type of this Handler.
Definition: AIStatefulTask.h:190
bool is_engine() const
Return true if this is an engine Handler.
Definition: AIStatefulTask.h:199
Contains extra data that depends on the type of the Handler.
Definition: AIStatefulTask.h:178
AIQueueHandle queue_handle
The actual thread pool queue when this is a thread pool Handler.
Definition: AIStatefulTask.h:180
Handle(AIEngine *engine_)
Construct a Handle from an AIEngine pointer.
Definition: AIStatefulTask.h:185
AIEngine * engine
The actual engine when this is an engine Handler.
Definition: AIStatefulTask.h:179
Handle()
Construct an uninitialized Handle.
Definition: AIStatefulTask.h:183
Handle(AIQueueHandle queue_handle_)
Construct a Handle from a thread pool handle.
Definition: AIStatefulTask.h:187