AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
thread.hh
Go to the documentation of this file.
1#ifndef _DRAMA2_THREAD_INC
2#define _DRAMA2_THREAD_INC
3
13/*
14 * History:
15 04-Mar-2014 - TJF - Original version
16
17 * The above ID is for Doxygen, this one has the format ACMM is looking for.
18 * "@(#) $Id$"
19 */
20
22#include <thread>
23#include <queue>
24#include <deque>
25#include <map>
26#include <chrono>
27#include <future>
28#include <condition_variable>
29#include <csignal>
30namespace drama {
31
32 class Path; /* drama::Path */
33
37 namespace thread {
38
39 /* @internal
40 * Information needed by threads waiting on conditions.
41 *
42 * Note - for kick events, the arg will stay around until
43 * the next event on this thread. This is because we can have
44 * multiple threads waiting for a kick event and we must ensure
45 * any argument is valid for all. We use a shared_ptr type to
46 * manage this.
47 */
48 struct WaitEventData {
49 sds::IdPtr arg;
50 TransEvtInfo eventInfo;
51 };
52
53 /* @internal
54 * A queue of WaitEventData.
55 */
56 typedef std::queue<WaitEventData> WaitEventDataQueue;
57
58
59 /* @internal
60 * The type of a pointer to a condition variable
61 */
62 typedef std::shared_ptr<std::condition_variable_any>
63 WaitEventCondPtrType;
64
65 /* @internal
66 * Information on events we are expecting related to a particular
67 * transaction.
68 */
69 struct WaitEventDetails {
70 std::thread::id _thread; // Thread which is waiting
71 DitsTransIdType _transId; // Transaction we are waiting on, 0 for kick.
72 WaitEventDataQueue _dataQueue; // Queue of transaction data.
73 WaitEventCondPtrType _condition; // Used to notify the thread
74 // of events.
75 bool _waiting; // Are we waiting.
76
77 Path *_pathObj; // Path message is along. IF not kick
78 DitsPathType _ditsPath; // Underlying DITS path.
79 DitsMsgType _type; // Message type, if not kick.
80 std::string _messName; // Message Name, if not kick
81
82
83 explicit WaitEventDetails(
85 Path *thePath);
86 bool DataAvail() const {
87 return !_dataQueue.empty();
88 }
89 ~WaitEventDetails() {
90#if 0
92 "WaitEvenDetails destructor - transid %p, this %p\n",
93 static_cast<void *>(_transId),
94 static_cast<void *>(this));
95#endif
96 }
97
98 };
99
100 /*
101 * A map of wait event details, indexed by thread id.
102 */
103 typedef std::map<std::thread::id, WaitEventDetails> WaitEventMapType;
104 typedef WaitEventMapType::iterator WaitEventMapIter;
105 typedef WaitEventMapType::const_iterator WaitEventMapIterConst;
106
107 class TMessHandler;
108
109
110 /*
111 * Return the number of events outstanding across all threads.
112 */
113 unsigned WaitEventMapGetEvents(std::weak_ptr<Task> theTask,
114 const WaitEventMapType &waitEventMap);
120 class ProcessInfo {
121 private:
122 std::shared_ptr<TMessHandler> _handler;
123 std::shared_ptr<Path> _pathObj;
124 const DitsMsgType _type; // Message type, if not kick.
125 const std::string _messName; // Message Name, if not kick
126 public:
134 ProcessInfo(std::shared_ptr<TMessHandler> handler,
135 const WaitEventDetails &details) :
136 _handler(handler),
137 _pathObj(details._pathObj, drama::nodel()),
138 _type(details._type),
139 _messName(details._messName) {
140
141 }
150 const TMessHandler &GetHandler() const {
151 return *_handler;
152 }
157 const Path &GetPath() const {
158 return *_pathObj;
159 }
164 DitsMsgType GetMessType() const {
165 return _type;
166 }
174 const char * GetMessTypeCStr() const {
175 return DitsGetMsgTypeStr(_type);
176 }
181 const std::string &GetMessName() const {
182 return _messName;
183 }
185 }; // class ProcessInfo.
186
187 /*
188 * Abstract class for objects used to process transaction events.
189 */
190 class TransEvtProcessor {
191 public:
208 virtual bool Process(ProcessInfo messInfo,
209 const TransEvtInfo & eventInfo,
210 const sds::IdPtr &arg) = 0;
211
223 virtual void NewTransaction(DitsMsgType msgType, DitsTransIdType tid) = 0;
245 virtual bool WaitTimeout(std::chrono::steady_clock::time_point *until);
246
248 virtual ~TransEvtProcessor() {}
249 };
250
255 class TSdsListToUserObj : public sds::PrintObjectCR {
256 private:
257 TMessHandler *_handler;
258 public:
263 TSdsListToUserObj(TMessHandler *messageHandler);
268 void Print(const std::string &line) const override;
269 };
281 class TMessHandler {
282 TSdsListToUserObj _sdsListToUserObj = this;
283 public:
284
287 TMessHandler& operator=(const TMessHandler &rhs) = delete;
288
291 TMessHandler(const TMessHandler &source) = delete;
292
293 TMessHandler() {}
294
300 virtual Task::mutexType & Lock() const = 0;
324 drama::Path *pathObj ) = 0;
348 virtual void MessageUser(const std::string &text) const = 0;
349
376 template<typename... Types>
377#ifndef RUNNING_DOXYGEN
378 D2_FMT_DEPRECATED("Replace MessageUser() by MessageUserF(). See MessageUserF() page for details.")
379#endif
380 void MessageUser(const char *format, Types... args) const {
381 /*
382 * Our approach is to write the output to a string, via
383 * SafePrintf(), then output that in one operation. Since
384 * std::ostream devices will then do the output in one operation.
385 */
386 std::stringstream sstrm;
388 MessageUser(sstrm.str());
389
390
391 }
392
409 template<typename... Args>
410 void MessageUserF(const fmt::format_string<Args...> fmt, Args&&... args) const {
411 MessageUser(fmt::vformat(fmt.get(), fmt::make_format_args(args...)));
412 }
413
436 virtual void WaitForTransaction(
437 std::weak_ptr<Task> theTask,
438 TransEvtInfo * const eventInfo,
439 TransEvtProcessor * const eventProcessor,
440 sds::IdPtr * const arg = nullptr) ;
441
442
465 virtual bool WaitForTransactionUntil(
466 std::weak_ptr<Task> theTask,
467 TransEvtInfo * const eventInfo,
468 TransEvtProcessor * const eventProcessor,
469 const std::chrono::steady_clock::time_point &until,
470 sds::IdPtr * const arg = nullptr);
471
472
473
480 virtual Dits___CurActType GetMessageContext() const = 0;
481
486 virtual std::shared_ptr<Task> GetTask() const = 0;
493 virtual const sds::PrintObjectCR &SdsListToUser() const;
494
497 virtual ~TMessHandler() {}
498
499
500 private:
501 /* Features used by WaitForTransaction()
502 */
503
512 virtual void ClearWait(bool complete) = 0;
513 /*
514 * Return a pointer to the event details for the specified thread.
515 */
516 virtual WaitEventDetails *FindWaitEventDetails(std::thread::id) = 0;
517
518 /*
519 *
520 * Initiate waiting for a transaction and return a pointer
521 * to the item the wait event details. Presumption is that
522 * SetupWaitEvent() has been invoked.
523 */
524 WaitEventDetails * WaitForTransactionStart();
525 /*
526 * The wait for transaction operation has finished - tidy up.
527 *
528 * @param Event details returned by WaitForTransactionStart()
529 * @param evenInfo Details on the event which caused the
530 * wait to finish are returned here.
531 * @param arg The output argument from the transaction, if any.
532 * An address of and sds::IdPtr is supplied.
533 * If you supply a null pointer, it is
534 * ignored. Otherwise, any argument to the
535 * transaction event is copied into here.
536 * If there is no argument to the
537 * transaction it will refer to a null
538 * SDS item.
539 */
540 void WaitForTransactionFinish(
541 const WaitEventData &details,
542 TransEvtInfo * const eventInfo,
543 sds::IdPtr * const arg);
544
545
546 }; // class TMessHandler
547
571 class AccessDrama {
572 Dits___CurActType _entryDetails;
573 Task::guardType _lock;
574 public:
587 ~AccessDrama();
588 };
589
595 class SignalBlocker {
596 sigset_t oldSet;
597 public:
605 };
607 /*
608 * Block all signals to the current thread.
609 */
610 extern void BlockSignals();
611
612
613 /* @internal
614 *
615 * Puts an entry in waitEventMap for this thread and the specified
616 * transaction id. If the transaction id is 0, then it is presumed
617 * the entry is for a kick.
618 *
619 * Thread/Lock Entry Info:
620 * May/may not be running in DRAMA message thread. (Probably not)
621 * DRAMA Lock Taken.
622 *
623 */
624 void SetupWaitEvent(DitsTransIdType id,
626 TMessHandler *h,
627 WaitEventMapType *waitEventMap);
628
629
630
716 const std::string &fileName,
717 const std::string &arguments="",
718 const std::string &node="",
719 int priority = 0,
720 bool absPriority = false,
721 bool setNames = true,
722 unsigned stackBytes = 0);
723
822 bool RunProgramWaitUntil(std::chrono::steady_clock::time_point until,
824 const std::string &fileName,
825 const std::string &arguments="",
826 const std::string &node="",
827 int priority = 0,
828 bool absPriority = false,
829 bool setNames = true,
830 unsigned stackBytes = 0);
831
832
833
834
835 } // namespace thread
836} // namespace drama
837
838#endif
A Class which provides access to DRAMA's message sending facilities.
Definition path.hh:689
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
Abstract class which is sub-classed to print SDS item listings.
Definition sds.hh:310
AccessDrama(const TMessHandler &messHandler)
Access the DRAMA context of a particular message handler object.
AccessDrama(Task::mutexType &taskLock)
Takes the DRAMA lock and saves the current context.
A class used by threads to access and enable the DRAMA context of an action or of a particular UFACE ...
Definition thread.hh:598
const Path & GetPath() const
Return the Path along which the message was sent.
Definition thread.hh:184
const std::string & GetMessName() const
Return the message name (Action name etc).
Definition thread.hh:208
DitsMsgType GetMessType() const
Return the type of the message that was sent.
Definition thread.hh:191
ProcessInfo(std::shared_ptr< TMessHandler > handler, const WaitEventDetails &details)
Construct one of these objects.
Definition thread.hh:161
const TMessHandler & GetHandler() const
Return the DRAMA Message handler object that was used to send the message.
Definition thread.hh:177
const char * GetMessTypeCStr() const
Return the type of the message that was sent as a C string.
Definition thread.hh:201
A class with information used by the TransEvtProcessor methods.
Definition thread.hh:147
SignalBlocker()
Constructor - Block signals in the current thread.
~SignalBlocker()
Destructor - read the signal mask settings to that when the constructor was run.
Constructing an object of this type will block all blockable UNIX signals in the current thread.
Definition thread.hh:622
virtual ~TMessHandler()
Destructor.
Definition thread.hh:524
virtual Dits___CurActType GetMessageContext() const =0
Get the DRAMA Context associated with the action/UFACE event.
virtual void SetupWaitEvent(DitsTransIdType tid, drama::Path *pathObj)=0
Sets up a wait event for this thread.
TMessHandler(const TMessHandler &source)=delete
Copy constructor - deleted.
virtual bool WaitForTransactionUntil(std::weak_ptr< Task > theTask, TransEvtInfo *const eventInfo, TransEvtProcessor *const eventProcessor, const std::chrono::steady_clock::time_point &until, sds::IdPtr *const arg=nullptr)
Block the current thread until a message for the transaction specified to SetupWaitEvent() occurs or ...
TMessHandler & operator=(const TMessHandler &rhs)=delete
Assignment operator - deleted.
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.
virtual void WaitForTransaction(std::weak_ptr< Task > theTask, TransEvtInfo *const eventInfo, TransEvtProcessor *const eventProcessor, sds::IdPtr *const arg=nullptr)
Block the current thread until a message for the transaction specified to SetupWaitEvent() occurs.
virtual std::shared_ptr< Task > GetTask() const =0
Get a reference to the DRAMA task we are part of.
void MessageUser(const char *format, Types... args) const
Use DRAMA to send a message to the user - safe format.
Definition thread.hh:407
void MessageUserF(const fmt::format_string< Args... > fmt, Args &&... args) const
Use DRAMA to send a message to the user - format using fmt::format.
Definition thread.hh:437
virtual void MessageUser(const std::string &text) const =0
Use DRAMA to send a message to the user.
virtual Task::mutexType & Lock() const =0
Reference the DRAMA Task lock.
This interface class must be implemented by classes which have threads waiting for messages.
Definition thread.hh:308
void Print(const std::string &line) const override
Prints one line of an SDS listing.
TSdsListToUserObj(TMessHandler *messageHandler)
Constructor.
Object used to print SDS objects using MessageUser from TMessHandler objects.
Definition thread.hh:282
DRAMA 2 include file - Message Handler class definition.
std::shared_ptr< Id > IdPtr
A shared pointer for sds::Id items.
Definition sds.hh:3613
bool RunProgramWaitUntil(std::chrono::steady_clock::time_point until, TMessHandler *messHandler, const std::string &fileName, const std::string &arguments="", const std::string &node="", int priority=0, bool absPriority=false, bool setNames=true, unsigned stackBytes=0)
Load and run a program using the DRAMA loading mechanisms.
void RunProgram(TMessHandler *messHandler, const std::string &fileName, const std::string &arguments="", const std::string &node="", int priority=0, bool absPriority=false, bool setNames=true, unsigned stackBytes=0)
Load and run a program using the DRAMA loading mechanisms.
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1339
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
Structure is used to store details about a DRAMA reschedule message relating to a transaction,...
Definition task.hh:134
Declare an operator to be used as a deletion operator by std::shared_ptr.
Definition task.hh:120