1#ifndef _DRAMA2_THREADACTION_INC
2#define _DRAMA2_THREADACTION_INC
47#include <condition_variable>
57 enum class ThreadSignalType {
66 struct DramaSignalDetails {
67 std::thread::id _fromThread;
68 ThreadSignalType _sigType;
70 DramaSignalDetails(ThreadSignalType
sigType) :
85 typedef std::deque<DramaSignalDetails> SignalDetailsQueue;
98 class _ThreadMessage :
public MessageHandler {
99 TAction *_threadHandlerObj;
118 TAction *_threadHandlerObj;
186 friend class _ThreadMessage;
187 friend class _ThreadKick;
190 std::future<void> _actionFuture;
197 std::weak_ptr<Task> _theTask;
224 _obeyRescheduleObj(
this),_kickMessageObj(
this) {
321 virtual void KickedWhenNotWaiting(sds::IdPtr
Arg);
344 virtual void SignaledWhenNotWaiting(sds::IdPtr
Arg);
353 return std::shared_ptr<Task>(_theTask);
363 return _theTask.expired();
411 template<
typename...
Types>
412#ifndef RUNNING_DOXYGEN
413 D2_FMT_DEPRECATED(
"Replace MessageUser() by MessageUserF(). See MessageUserF() page for details.")
422 std::stringstream
sstrm;
444 template<
typename...
Args>
461 virtual const sds::PrintObjectCR &
SdsListToUser()
const override {
476 double GetTimeout()
const {
512 SignalAmWaitingForKick();
522 std::shared_ptr<Task>(_theTask)->Lock());
524 std::thread::id
threadId(std::this_thread::get_id());
544 *
event =
details.eventInfo.entryReason;
552 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
D2LOG_DRAMA2,
553 "d2::TACT::WaitForEvent",
589 template <
class Rep,
class Period>
590 bool WaitForEventTimeoutIn(
592 const std::chrono::duration<Rep,Period>&
rel_time,
599 SignalAmWaitingForKick();
604 std::shared_ptr<Task>(_theTask)->Lock());
605 std::thread::id
threadId(std::this_thread::get_id());
621 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
623 "d2::TACT::WaitEventTOIn",
624 "Timeout waiting for signal/kick");
630 *
event = EntryCode::DramaAbortWaits;
636 *
event =
details.eventInfo.entryReason;
644 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
D2LOG_DRAMA2,
645 "d2::TACT::WaitEventTOIn",
646 "kick/signal received");
676 bool WaitForEventTimeoutIn(
681 return WaitForEventTimeoutIn(
event, std::chrono::seconds(
seconds), arg);
718 template <
class Clock,
class Duration>
719 bool WaitEventTimeoutAt(
721 const std::chrono::time_point<Clock,Duration>&
abs_time,
729 SignalAmWaitingForKick();
734 std::shared_ptr<Task>(_theTask)->Lock());
735 std::thread::id
threadId(std::this_thread::get_id());
751 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
D2LOG_DRAMA2,
752 "d2::TACT::WaitEventTOAT",
753 "Timeout waiting for signal/kick");
756 *
event = EntryCode::DramaAbortWaits;
761 *
event =
details.eventInfo.entryReason;
770 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
772 "d2::TACT::WaitEventTOAt",
773 "Signal/Kick received");
797 void WaitForKick(
sds::IdPtr *
const arg=
nullptr) {
801 WaitForEvent(&
event, arg);
805 "TAction::WaitForKick - signal received instead of kick, application programming error. You may want WaitForEvent()");
834 template <
class Rep,
class Period>
835 bool WaitForKickTimeoutIn(
836 const std::chrono::duration<Rep,Period>&
rel_time,
847 "TAction::WaitForKickTimeoutIn - signal received instead of kick, application programming error. You may want WaitForEventTimeoutIn()");
872 bool WaitForKickTimeoutIn(
876 return WaitForKickTimeoutIn(std::chrono::seconds(
seconds), arg);
907 template <
class Clock,
class Duration>
908 bool WaitKickForTimeoutAt(
909 const std::chrono::time_point<Clock,Duration>&
abs_time,
921 "TAction::WaitForKickTimeoutAt - signal received instead of kick, application programming error. You may want WaitForEventTimeoutAt()");
972 _outArg = arg.Copy();
973 _outArgDelete =
true;
977 _outArg.ShallowCopy(arg);
978 _outArgDelete =
false;
987 void SetExitOnCompletion() {
994 void ClearExitOnCompletion() {
1010 _outArg.ShallowCopy(arg,
true);
1011 _outArgDelete =
true;
1071 WaitEventDetails *SetupWaitForKick() {
1078 SignalAmWaitingForKick();
1084 std::shared_ptr<Task>(_theTask)->Lock());
1085 std::thread::id
threadId(std::this_thread::get_id());
1109 bool DoWaitForKick(WaitEventDetails *
waitEvent,
1121 std::shared_ptr<Task>(_theTask)->Lock());
1135 std::shared_ptr<Task>(_theTask)->Logger().LogNF(
1137 "d2::TACT::DoWaitKick",
1145 if (
details.eventInfo.entryReason ==
1146 EntryCode::DramaAbortWaits)
1159 _ThreadMessage _obeyRescheduleObj;
1160 _ThreadKick _kickMessageObj;
1169 std::string _actionName;
1189 bool _exitTask =
false;
1194 bool _outArgDelete =
false;
1195 bool _outArgSet =
false;
1203 SignalDetailsQueue _signalQueue;
1209 WaitEventMapType _waitEventMap;
1224 void SignalDrama(ThreadSignalType
why);
1229 void SignalAmWaitingForKick();
1236 Request ProcessDrama2Signal();
1240 Request ProcessSubsidiaryMessage();
1250 void ClearWait(
bool complete)
override;
1255 WaitEventDetails *FindWaitEventDetails(std::thread::id)
1265 unsigned WakeUpWaitingThreads(
sds::IdPtr arg);
1271 void ActionThreadComplete();
1284 void OrphanOutstandingEvents();
1293 unsigned GetKickCount()
const {
1309 void ResetKickCount();
1325 std::string GetActionName()
const {
1355 TAction(dramaTask, 0), _func(func) { }
1364 _func(
this, obeyArg);
1393 bool _wasKicked =
false;
1394 bool _waiting =
false;
1395 bool _threadThrew =
false;
1396 TAction *_theAction =
nullptr;
1399 std::future<void> _threadFuture;
1404 std::condition_variable_any _threadReadyCond;
1405 WaitEventDetails *_waitEvent =
nullptr;
1464 virtual bool Kicked(
const sds::Id & arg);
1480 bool ThreadThrewException()
const {
1481 return _threadThrew;
1488 virtual ~KickNotifier();
1492 KickNotifier& operator=(
const KickNotifier &rhs) =
delete;
1495 KickNotifier(
const KickNotifier &source) =
delete;
1508 virtual int RunDramaHasExited()
override;
1528 bool JoinThreads(std::chrono::steady_clock::time_point until)
override;
void MessageUserF(const fmt::format_string< Args... > fmt, Args &&... args)
Use DRAMA to send a message to the user - format using fmt::format.
Definition messagehandler.hh:404
virtual void PutObeyHandler(MessageHandlerPtr obj)
Put a message handler object for the next Obey reschedule event.
Definition messagehandler.hh:690
MessageHandler & operator=(const MessageHandler &rhs)=delete
Copy operator deleted.
virtual std::shared_ptr< Task > GetTask() const
Returns a pointer to the task.
Definition messagehandler.hh:439
virtual void PutKickHandler(MessageHandlerPtr obj)
Put a message handler object for the next Kick event.
Definition messagehandler.hh:709
virtual void MessageUser(const std::string &text) const
Use DRAMA to send a message to the user.
MessageHandler()
Create a DRAMA action/message handler object.
Definition messagehandler.hh:177
virtual const sds::PrintObjectCR & SdsListToUser() const
Get a reference to an SDS printer object which can be used to list an SDS object using MessageUser.
void SendTrigger(const sds::Id &arg) const
Send a trigger message to the parent action.
void SetReturnArg(const sds::Id &arg, bool copy=true)
Set the argument to be sent as part of the action completion message.
Definition messagehandler.hh:616
A class which implements a DRAMA Message Handler.
Definition messagehandler.hh:141
A Class which provides access to DRAMA's message sending facilities.
Definition path.hh:689
Class used by Obey and Kick handlers to indicate rescheduling requirements.
Definition request.hh:78
Class used to arrange for notifications when the RunDrama exits.
Definition task.hh:393
std::unique_lock< mutexType > uniqueLockType
Defines the type of a unique_lock type using our mutex type.
Definition task.hh:474
std::recursive_timed_mutex mutexType
Defines the type of our mutex.
Definition task.hh:466
std::lock_guard< mutexType > guardType
Defines the type of a lock guard using our mutex type.
Definition task.hh:471
A class which implements a DRAMA task.
Definition task.hh:452
virtual Id Copy() const
Factory constructor method Id Copy constructor.
virtual void ShallowCopy(const Id &source)
Shallow copy from a const sds::Id which will outlive this object.
Definition sds.hh:2521
A C++ Interface to the handling SDS structures.
Definition sds.hh:428
Abstract class which is sub-classed to print SDS item listings.
Definition sds.hh:310
KickNotifier & operator=(const KickNotifier &rhs)=delete
Assignment operator - deleted.
KickNotifier(TAction *action)
KickNotifier constructor.
virtual bool Kicked(const sds::Id &arg)
Method is invoked when a Kick occurs.
bool ThreadThrewException() const
Return true if the thread has died after thrown an exception.
Definition threadaction.hh:1507
bool JoinThreads(std::chrono::steady_clock::time_point until) override
Invoked when the drama::task::RunDrama() loop exits.
virtual int RunDramaHasExited() override
Invoked when the drama::task::RunDrama() method exits.
virtual ~KickNotifier()
Destructor.
bool WasKicked()
Indicates if the action was kicked.
Definition threadaction.hh:1498
KickNotifier(const KickNotifier &source)=delete
Copy constructor - deleted.
An object used to obtain notifications of kicks.
Definition threadaction.hh:1418
TActionViaFunctor(std::weak_ptr< Task > dramaTask, const ThreadActionFunction func)
Initialize object with the specified function, which meets the ThreadActionFunction prototype.
Definition threadaction.hh:1380
void ActionThread(const drama::sds::Id &obeyArg) override
Invoke function.
Definition threadaction.hh:1390
This class is used to creating TAction objects referring to functions.
Definition threadaction.hh:1370
bool WaitForKickTimeoutIn(const std::chrono::duration< Rep, Period > &rel_time, sds::IdPtr *const arg=0)
Block the current thread until a kick for the action is received or a duration has passed.
Definition threadaction.hh:862
void MessageUser(const std::string &text) const override
Use DRAMA to send a message to the user.
virtual const sds::PrintObjectCR & SdsListToUser() const override
Get a reference to an SDS printer object which can be used to list an SDS object using MessageUser.
Definition threadaction.hh:488
TAction(const TAction &source)=delete
Copy constructor - deleted.
void WaitForKick(sds::IdPtr *const arg=nullptr)
Block the current thread until a kick for the action is received.
Definition threadaction.hh:824
void SetTimeout(double newTimeout)
Set a new timeout.
Definition threadaction.hh:514
double GetTimeout() const
Return the current action timeout.
Definition threadaction.hh:503
bool WaitKickForTimeoutAt(const std::chrono::time_point< Clock, Duration > &abs_time, sds::IdPtr *const arg=0)
Block the current thread until a kick for the action is received or until a given time.
Definition threadaction.hh:935
TAction & operator=(const TAction &rhs)=delete
Assignment operator - deleted.
void MessageUserF(const fmt::format_string< Args... > fmt, Args &&... args)
Use DRAMA to send a message to the user - format using fmt::format.
Definition threadaction.hh:472
void PutKickHandler(MessageHandlerPtr obj) override final
We cannot change the kick handler in a threaded action, it does not make sense.
void SetupWaitEvent(DitsTransIdType tid, drama::Path *pathObj) override
Sets up a wait event for this thread.
virtual ~TAction()
TAction destructor.
bool WaitEventTimeoutAt(EntryCode *event, const std::chrono::time_point< Clock, Duration > &abs_time, sds::IdPtr *const arg=0)
Block the current thread until a signal/kick for the action is received or until a given time.
Definition threadaction.hh:746
void SetExitOnCompletion()
Set exit on completion.
Definition threadaction.hh:1014
unsigned GetKickCount() const
Returns the number of times this action has been kicked since started or the last reset of the count.
Definition threadaction.hh:1320
void AbortMessageWaits(StatusType status)
Tells any thread waiting for messages to abort the wait event.
bool WaitForEventTimeoutIn(EntryCode *event, unsigned seconds, sds::IdPtr *const arg=0)
Block the current thread until a signal/kick for the action is received or a duration in seconds has ...
Definition threadaction.hh:703
bool DoWaitForKick(WaitEventDetails *waitEvent, sds::IdPtr *const arg=nullptr)
Wait for a kick event with the waitEvent details given.
Definition threadaction.hh:1136
void SetReturnArg(sds::Id *arg)
Set the argument to be sent as part of the action completion message.
Definition threadaction.hh:1035
void ClearExitOnCompletion()
Clear exit on completion.
Definition threadaction.hh:1021
void MessageUser(const char *format, Types... args)
Use DRAMA to send a message to the user - safe format.
Definition threadaction.hh:442
bool HasTaskExpired() const noexcept
Indicate if the underlying DRAMA task weak pointer has expired.
Definition threadaction.hh:389
std::shared_ptr< Task > GetTask() const override
Get a reference to the DRAMA task we are part of.
Definition threadaction.hh:379
TAction(std::weak_ptr< Task > dramaTask, double timeout=0)
Create a DRAMA action/message handler object which runs a thread when the Obey message is received.
Definition threadaction.hh:249
void WaitForEvent(EntryCode *event, sds::IdPtr *const arg=nullptr)
Block the current thread until a kick/signal message for the action is received.
Definition threadaction.hh:533
std::string GetActionName() const
Return the name of the action this thread is implementing.
Definition threadaction.hh:1352
void SetReturnArg(const sds::Id &arg, bool copy=true)
Set the argument to be sent as part of the action completion message.
Definition threadaction.hh:995
WaitEventDetails * SetupWaitForKick()
Set up to wait for a kick message.
Definition threadaction.hh:1098
void SendTrigger(const sds::Id &arg) const
Send a trigger message to the parent action.
Dits___CurActType GetMessageContext() const override
Get the DRAMA Context associated with the action event.
bool WaitForKickTimeoutIn(unsigned seconds, sds::IdPtr *const arg=0)
Block the current thread until a kick for the action is received or a duration in seconds has passed.
Definition threadaction.hh:899
void PutObeyHandler(MessageHandlerPtr obj) override final
We cannot change the obey handler in a threaded action, it does not make sense as the action never re...
bool WaitForEventTimeoutIn(EntryCode *event, const std::chrono::duration< Rep, Period > &rel_time, sds::IdPtr *const arg=0)
Block the current thread until a signal/kick for the action is received or a duration has passed.
Definition threadaction.hh:617
Task::mutexType & Lock() const override
Get a reference the DRAMA Task lock.
void ResetKickCount()
Returns a shared pointer to the last kick message argument.
A class which implements a DRAMA Action with runs a thread.
Definition threadaction.hh:204
virtual const sds::PrintObjectCR & SdsListToUser() const
Get a reference to an SDS printer object which can be used to list an SDS object using MessageUser.
This interface class must be implemented by classes which have threads waiting for messages.
Definition thread.hh:308
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:90
#define D2LOG_DRAMA2
DRAMA 2 events - thread events etc.
Definition logger.hh:107
DRAMA 2 include file - Message Handler class definition.
std::shared_ptr< Id > IdPtr
A shared pointer for sds::Id items.
Definition sds.hh:3613
std::function< void(TAction *, const sds::Id &)> ThreadActionFunction
Type used for functions specified drama::Task::Add().
Definition task.hh:102
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1339
EntryCode
Entry type code - indicates the type of a DRAMA event.
Definition entryinfo.hh:67
@ Kick
Action has been kicked.
@ Complete
Obey/Kick etc message completed.
std::shared_ptr< MessageHandler > MessageHandlerPtr
This type is used for passing MessageHandler object addresses around.
Definition messagehandler.hh:96
void SafePrintf(std::ostream &ostream, const char *str)
Safe formatted write to a stream.
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:99
DRAMA 2 include file - Code common to DRAMA 2 features supporting threading.