STLdoc
STLdocumentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
agents.h
Go to the documentation of this file.
1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 * ==--==
7 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
8 *
9 * agents.h
10 *
11 * Main public header file for ConcRT's asynchronous agents layer. This is the only header file a
12 * C++ program must include to use asynchronous agents.
13 *
14 * The core runtime, Parallel Patterns Library (PPL), and resource manager are defined in separate header files.
15 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
16 ****/
17 
18 #pragma once
19 
20 #include <crtdefs.h>
21 #include <concrt.h>
22 #include <stdexcept>
23 #include <functional>
24 #include <tuple>
25 #include <type_traits>
26 #include <vector>
27 #include <concurrent_queue.h>
28 
29 #define _AGENTS_H
30 
31 #pragma pack(push,_CRT_PACKING)
32 #pragma warning(push)
33 #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
34 #pragma warning(disable: 4702) // Unreachable code - needed for retail version code path
35 #pragma warning(disable: 4297) // Function expected not to throw but does
36 // Forward declarations
37 
42 
43 namespace Concurrency
44 {
50 
51 typedef __int32 runtime_object_identity;
52 
57 
58 typedef ::Concurrency::details::_NonReentrantPPLLock::_Scoped_lock _NR_lock;
59 
64 
65 typedef ::Concurrency::details::_ReentrantPPLLock::_Scoped_lock _R_lock;
66 
67 
68 //***************************************************************************
69 // Internal namespace:
70 //
71 // ::Concurrency::details contains definitions to support routines in the public namespaces and macros.
72 // Clients should not directly interact with this namespace.
73 //***************************************************************************
74 
75 namespace details
76 {
77  //**************************************************************************
78  // Core Messaging Support:
79  //**************************************************************************
80 
81  //
82  // A base class to derive from that keeps unique IDs on its derived classes
83  //
84  class _Runtime_object : public _AllocBase
85  {
86  public:
87  // Creates a new runtime object.
89 
90  // Creates a runtime object from an identity.
92 
93  // Gets the runtime object identity.
95  {
96  return _M_id;
97  }
98 
99  protected:
100  // The runtime object identity.
102  };
103 
104  // A queue used to hold the messages for the messaging blocks
105  template<class _Message>
106  class _Queue : public _AllocBase
107  {
108  protected:
109  // A pointer to the head of the queue.
110  _Message * _M_pHead;
111 
112  // A pointer to a pointer to the tail of the queue.
113  _Message ** _M_ppTail;
114 
115  // The number of elements presently stored in the queue.
116  size_t _M_count;
117 
118  public:
119  typedef typename _Message type;
120 
121  // Create a Queue
122  _Queue() : _M_pHead(NULL), _M_ppTail(&_M_pHead), _M_count(0)
123  {
124  }
125 
126  // Destroy the queue
128  {
129  }
130 
131  // Returns the count of items in the queue
132  size_t _Count() const
133  {
134  return _M_count;
135  }
136 
137  // Add an item to the tail of the queue
138  //
139  // Returns a Boolean indicating whether the operation succeeded.
140  bool _Enqueue(_Message *_Element)
141  {
142  _CONCRT_ASSERT(_Element->_M_pNext == NULL);
143  _CONCRT_ASSERT(*_M_ppTail == NULL);
144 
145  *_M_ppTail = _Element;
146  _Element->_M_pNext = NULL;
147  _M_ppTail = &(_Element->_M_pNext);
148  _M_count++;
149 
150  return true;
151  }
152 
153  // Remove the specified element from the queue
154  //
155  // Returns a Boolean indicating whether the operation succeeded, that is, the message was found in the queue.
156  bool _Remove(_Message * _OldElement)
157  {
158  bool _Result = false;
159 
160  _CONCRT_ASSERT(_OldElement != NULL);
161 
162  if (_M_pHead == _OldElement)
163  {
164  _M_pHead = _OldElement->_M_pNext;
165  if (_M_pHead == NULL)
166  {
167  _M_ppTail = &_M_pHead;
168  }
169 
170  _OldElement->_M_pNext = NULL;
171  _M_count--;
172  _Result = true;
173  }
174  else
175  {
176  _Message * _Next = NULL;
177  for (_Message * _Node = _M_pHead; _Node != NULL; _Node = _Next)
178  {
179  _Next = _Node->_M_pNext;
180 
181  if (_Node->_M_pNext == _OldElement)
182  {
183  _Node->_M_pNext = _OldElement->_M_pNext;
184  // if this is the last element of the _Queue
185  if (_Node->_M_pNext == NULL && _M_count == 1)
186  {
187  _M_ppTail = &_M_pHead;
188  }
189 
190  _OldElement->_M_pNext = NULL;
191  _M_count--;
192  _Result = true;
193  break;
194  }
195  }
196  }
197 
198  return _Result;
199  }
200 
201  // Dequeue an item from the head of queue
202  //
203  // Returns a pointer to the message found at the head of the queue.
204  _Message * _Dequeue()
205  {
206  if (_M_pHead == NULL)
207  {
208  return NULL;
209  }
210 
211  _Message * _Result = _M_pHead;
212 
213  _M_pHead = _Result->_M_pNext;
214  if (_M_pHead == NULL)
215  {
216  _M_ppTail = &_M_pHead;
217  }
218 
219  _Result->_M_pNext = NULL;
220  _M_count--;
221  return _Result;
222  }
223 
224  // Return the item at the head of the queue, without dequeuing
225  //
226  // Returns a pointer to the message found at the head of the queue.
227  _Message * _Peek()
228  {
229  return _M_pHead;
230  }
231 
232  // Return true if the ID matches the message at the head of the queue
233  bool _Is_head(runtime_object_identity _MsgId)
234  {
235  // Peek at the next message in the message buffer. Use it to
236  // check if the IDs match
237  _Message * _Msg = _M_pHead;
238 
239  if (_Msg == NULL || _Msg->msg_id() != _MsgId)
240  {
241  return false;
242  }
243 
244  return true;
245  }
246  };
247 
248  //
249  // _Dynamic_array implements a container very similar to std::vector.
250  // However, it exposes a reduced subset of functionality that is
251  // geared towards use in network_link_registry. The array access is not
252  // thread-safe.
253  //
254  template<class _Type>
256  {
257  public:
258 
260 
261  typedef _Type& reference;
262  typedef _Type const& const_reference;
263 
264  //
265  // Construct a dynamic array
266  //
268  {
269  _Init();
270  }
271 
272  //
273  // Release any resources used by dynamic array
274  //
276  {
277  _Clear();
278  }
279 
280  //
281  // Assignment operator. Copy the contents of _Right
282  //
283  _Myt& operator=(const _Myt& _Right)
284  {
285  if (this != &_Right)
286  {
287  // Remove all the elements
288  _Clear();
289 
290  // Allocate space for the new elements
291  size_t _Size = _Right._Size();
292  _Grow(_Size);
293 
294  // Copy over the new elements
295  for (size_t _I=0; _I < _Size; _I++)
296  {
297  _Push_back(_Right[_I]);
298  }
299  }
300 
301  return *this;
302  }
303 
304  //
305  // Clear all the elements in the array
306  //
307  void _Clear()
308  {
309  if (_M_array != NULL)
310  {
311  delete [] _M_array;
312  _Init();
313  }
314  }
315 
316  //
317  // Add an element to the end of the array
318  //
319  void _Push_back(_Type const& _Element)
320  {
321  if (_M_index >= _M_size)
322  {
323  // Not enough space. Grow the array
324  size_t _NewSize = (_M_index + 1) * _S_growthFactor;
325  _Grow(_NewSize);
326  }
327 
329  _M_array[_M_index] = _Element;
330  _M_index++;
331  }
332 
333  //
334  // Index operation. Retrieve an element at the specified index. No bounds check is done.
335  //
336  reference operator[](size_t _Pos)
337  {
338  _CONCRT_ASSERT(_Pos < _M_size);
339  return _M_array[_Pos];
340  }
341 
342  //
343  // Index operation. Retrieve an element at the specified index. No bounds check is done.
344  //
345  const_reference operator[](size_t _Pos) const
346  {
347  _CONCRT_ASSERT(_Pos < _M_size);
348  return _M_array[_Pos];
349  }
350 
351  //
352  // Returns the count of elements in the array
353  //
354  size_t _Size() const
355  {
356  return _M_index;
357  }
358 
359  //
360  // Swap the contents of this array with _Right
361  //
362  void _Swap(_Myt& _Right)
363  {
364  if (this != &_Right)
365  {
366  // Swap the details.
367  _Type * _Array = _M_array;
368  size_t _Index = _M_index;
369  size_t _Size = _M_size;
370 
371  _M_array = _Right._M_array;
372  _M_index = _Right._M_index;
373  _M_size = _Right._M_size;
374 
375  _Right._M_array = _Array;
376  _Right._M_index = _Index;
377  _Right._M_size = _Size;
378  }
379  }
380 
381  private:
382  //
383  // Initialize the array
384  //
385  void _Init()
386  {
387  _M_array = NULL;
388  _M_index = 0;
389  _M_size = 0;
390  }
391 
392  //
393  // Grow the array to the given size. The old elements are copied over.
394  //
395  void _Grow(size_t _NewSize)
396  {
397  _CONCRT_ASSERT( _NewSize > _M_size );
398 
399  _Type * _Array = new _Type[_NewSize];
400 
401  if (_M_array != NULL)
402  {
403  // Copy over the elements
404  for (size_t _I = 0; _I < _M_size; _I++)
405  {
406  _Array[_I] = _M_array[_I];
407  }
408 
409  delete [] _M_array;
410  }
411 
412  _M_array = _Array;
413  _M_size = _NewSize;
414  }
415 
416  // Private data members
417 
418  // Array of elements
419  _Type * _M_array;
420 
421  // Index where the next element should be inserted
422  size_t _M_index;
423 
424  // Capacity of the array.
425  size_t _M_size;
426 
427  static const int _S_growthFactor = 2;
428  };
429 
430  //
431  // Returns an identifier for the given object that could be used
432  // in an ETW trace (call to _Trace_agents)
433  //
434  template <class _Type>
435  __int64 _Trace_agents_get_id(_Type * _PObject)
436  {
437  return reinterpret_cast<__int64>(_PObject);
438  }
439 
440 } // namespace details
441 
442 //**************************************************************************
443 // Public Namespace:
444 //
445 // Anything in the Concurrency namespace is intended for direct client consumption.
446 //
447 //**************************************************************************
448 
449 //
450 // Forward declarations:
451 //
452 template<class _Type> class ISource;
453 template<class _Type> class ITarget;
454 
455 //**************************************************************************
456 // Network link registry
457 //**************************************************************************
458 
459 // Forward declaration for use in the iterator
460 template<class _Block> class network_link_registry;
461 
469 
470 template<class _Block>
472 {
473 public:
474 
477 
478  // Element type
479  typedef _Block* _EType;
480 
481  // Const iterator - iterator shall not be used to modify the links
482  typedef _EType const& const_reference;
483  typedef _EType const* const_pointer;
484 
488 
489  _Network_link_iterator(_MyContainer * _PNetwork_link, size_t _Index) : _M_pNetwork_link(_PNetwork_link), _M_index(_Index), _M_value(NULL)
490  {
492  }
493 
497 
499  {
501  _M_index = _Right._M_index;
502  }
503 
507 
508  _Myt const& operator=(_Myt const& _Right)
509  {
511  _M_index = _Right._M_index;
512  return *this;
513  }
514 
521 
522  const_reference operator*()
523  {
525  return _M_value;
526  }
527 
534 
535  const_pointer operator->() const
536  {
537  return (&**this);
538  }
539 
547 
548  _Myt& operator++()
549  {
550  ++_M_index;
552  return (*this);
553  }
554 
562 
563  _Myt operator++(int)
564  {
565  _Myt _Tmp = *this;
566  ++*this;
567  return (_Tmp);
568  }
569 
570 private:
571 
572  // Pointer to the underlying container (network link registry)
573  _MyContainer * _M_pNetwork_link;
574 
575  // Current index
576  size_t _M_index;
577 
578  // Current value
579  _EType _M_value;
580 };
581 
594 
595 template<class _Block>
597 {
598 public:
599 
603 
604  typedef typename _Block type;
605 
609 
610  typedef _Block * _EType;
611 
616 
617  typedef _EType const& const_reference;
618 
623 
624  typedef _EType const* const_pointer;
625 
626  // Make the iterators friends so that they can access some of the
627  // private routines such as _Get_element.
628 
629  friend class _Network_link_iterator<_Block>;
630 
635 
637 
645 
646  virtual void add(_EType _Link) = 0;
647 
658 
659  virtual bool remove(_EType _Link) = 0;
660 
672 
673  virtual bool contains(_EType _Link) = 0;
674 
682 
683  virtual size_t count() = 0;
684 
695 
696  virtual iterator begin() = 0;
697 
698 protected:
699 
707 
708  virtual void _Next_index(size_t& _Index) = 0;
709 
720 
721  virtual _EType _Get_element(size_t _Index) const = 0;
722 };
723 
732 
733 template<class _Block>
735 {
736 public:
737 
741 
743  {
744  }
745 
753 
755  {
756  // It is an error to delete link registry with links
757  // still present
758  if (count() != 0)
759  {
760  throw invalid_operation("Deleting link registry before removing all the links");
761  }
762  }
763 
774 
776  {
777  if (_Link == NULL)
778  {
779  return;
780  }
781 
782  // Only one link can be added.
783  if (_M_connectedLink != NULL)
784  {
785  throw invalid_link_target("_Link");
786  }
787 
789  }
790 
800 
801  virtual bool remove(typename network_link_registry<_Block>::_EType _Link)
802  {
803  if ((_Link != NULL) && (_M_connectedLink == _Link))
804  {
806  return true;
807  }
808 
809  return false;
810  }
811 
821 
823  {
824  return ((_Link != NULL) && (_M_connectedLink == _Link));
825  }
826 
833 
834  virtual size_t count()
835  {
836  return (_M_connectedLink == NULL) ? 0 : 1;
837  }
838 
848 
850  {
851  return (typename network_link_registry<_Block>::iterator(this, 0));
852  }
853 
854 protected:
855 
863 
864  virtual void _Next_index(size_t& _Index)
865  {
866  if (_M_connectedLink == NULL)
867  {
868  _Index++;
869  }
870  }
871 
882 
883  virtual typename network_link_registry<_Block>::_EType _Get_element(size_t _Index) const
884  {
885  if (_Index == 0)
886  {
887  return _M_connectedLink;
888  }
889 
890  return NULL;
891  }
892 
893 private:
894 
895  // A single pointer is used to hold the link
897 };
898 
907 
908 template<class _Block>
910 {
911 public:
912 
916 
918  {
919  }
920 
928 
930  {
931  // It is an error to delete link registry with links
932  // still present
933  if (count() != 0)
934  {
935  throw invalid_operation("Deleting link registry before removing all the links");
936  }
937  }
938 
951 
952  void set_bound(size_t _MaxLinks)
953  {
954  _CONCRT_ASSERT(count() == 0);
955  _M_maxLinks = _MaxLinks;
956  }
957 
969 
971  {
972  if (_Link == NULL)
973  {
974  return;
975  }
976 
977  _Add(_Link);
978  }
979 
989 
990  virtual bool remove(typename network_link_registry<_Block>::_EType _Link)
991  {
992  if (_Link == NULL)
993  {
994  return false;
995  }
996 
997  return (_Remove(_Link));
998  }
999 
1009 
1011  {
1012  if (_Link == NULL)
1013  {
1014  return false;
1015  }
1016 
1017  return (_Find(_Link) < _M_vector._Size());
1018  }
1019 
1026 
1027  virtual size_t count()
1028  {
1029  return _Count();
1030  }
1031 
1041 
1043  {
1044  return (typename network_link_registry<_Block>::iterator(this, 0));
1045  }
1046 
1047 protected:
1048 
1056 
1057  virtual void _Next_index(size_t& _Index)
1058  {
1059  size_t _Size = _M_vector._Size();
1060  while (_Index < _Size)
1061  {
1062  if (_M_vector[_Index] != NULL)
1063  {
1064  break;
1065  }
1066 
1067  ++_Index;
1068  }
1069  }
1070 
1081 
1082  virtual typename network_link_registry<_Block>::_EType _Get_element(size_t _Index) const
1083  {
1084  if (_Index < _M_vector._Size())
1085  {
1086  return _M_vector[_Index];
1087  }
1088 
1089  return NULL;
1090  }
1091 
1092 private:
1093 
1100 
1102  {
1103  size_t _Size = _M_vector._Size();
1104  size_t _Insert_pos = 0;
1105 
1106  _CONCRT_ASSERT(_Link != NULL);
1107 
1108  // If max links is set, ensure that inserting the new
1109  // link will not exceed the bound.
1110  if ((_M_maxLinks != _NOT_SET) && ((_Size+1) > (size_t) _M_maxLinks))
1111  {
1112  throw invalid_link_target("_Link");
1113  }
1114 
1115  for (size_t _Index = 0; _Index < _Size; _Index++)
1116  {
1117  if (_M_vector[_Index] != NULL)
1118  {
1119  // We want to find the first NULL entry after all the
1120  // non-NULL entries.
1121  _Insert_pos = _Index + 1;
1122 
1123  // Throw if duplicate entry is found
1124  if (_M_vector[_Index] == _Link)
1125  {
1126  throw invalid_link_target("_Link");
1127  }
1128  }
1129  }
1130 
1131  if (_Insert_pos < _Size)
1132  {
1133  _M_vector[_Insert_pos] = _Link;
1134  }
1135  else
1136  {
1137  _M_vector._Push_back(_Link);
1138  }
1139  }
1140 
1150 
1152  {
1153  _CONCRT_ASSERT(_Link != NULL);
1154 
1155  for (size_t _Index = 0; _Index < _M_vector._Size(); _Index++)
1156  {
1157  if (_M_vector[_Index] == _Link)
1158  {
1159  _M_vector[_Index] = NULL;
1160 
1161  // If max links is set, prevent new additions to the registry
1162  if (_M_maxLinks != _NOT_SET && _M_maxLinks > 0)
1163  {
1164  // Setting the bound to 0. This causes add to always throw.
1165  _M_maxLinks = 0;
1166  }
1167 
1168  return true;
1169  }
1170  }
1171 
1172  return false;
1173  }
1174 
1175 
1185 
1187  {
1188  size_t _Index = 0;
1189  for (_Index = 0; _Index < _M_vector._Size(); _Index++)
1190  {
1191  if (_M_vector[_Index] == _Link)
1192  {
1193  break;
1194  }
1195  }
1196 
1197  return _Index;
1198  }
1199 
1206 
1207  size_t _Count() const
1208  {
1209  size_t _Count = 0;
1210 
1211  for (size_t _Index = 0; _Index < _M_vector._Size(); _Index++)
1212  {
1213  if (_M_vector[_Index] != NULL)
1214  {
1215  _Count++;
1216  }
1217  }
1218 
1219  return _Count;
1220  }
1221 
1222  static const size_t _NOT_SET = SIZE_MAX;
1223 
1224  // Maximum number of links allowed.
1225  size_t _M_maxLinks;
1226 
1227  // ::Concurrency::details::_Dynamic_array is used to hold the links
1229 };
1230 
1231 // Forward declaration for the iterator
1232 template<class _LinkRegistry> class source_link_manager;
1233 
1240 
1241 template<class _LinkRegistry>
1243 {
1244 public:
1245 
1246  typedef typename _LinkRegistry::type _Block;
1247 
1250 
1251  // Element type
1252  typedef _Block* _EType;
1253 
1254  // Const iterator - iterator shall not be used to modify the links
1255  typedef _EType const& const_reference;
1256  typedef _EType const* const_pointer;
1257 
1261 
1262  _Source_link_iterator(_MyContainer * _PNetwork_link, size_t _Index) : _M_pNetwork_link(_PNetwork_link), _M_index(_Index), _M_sentinel(NULL)
1263  {
1264  // Take a snapshot of the link registry. This will reference the registry.
1266  }
1267 
1271 
1273  {
1274  if (_M_pNetwork_link != NULL)
1275  {
1277  }
1278  }
1282 
1284  {
1286  _M_index = _Right._M_index;
1287  _M_array = _Right._M_array;
1288 
1290  }
1291 
1295 
1296  _Myt const& operator=(_Myt const& _Right)
1297  {
1298  _MyContainer * _OldContainer = _M_pNetwork_link;
1299  _CONCRT_ASSERT(_OldContainer != NULL);
1300 
1302  _M_index = _Right._M_index;
1303  _M_array = _Right._M_array;
1304 
1305  if (_OldContainer != _M_pNetwork_link)
1306  {
1307  _OldContainer->release();
1309  }
1310 
1311  return *this;
1312  }
1313 
1320 
1321  const_reference operator*()
1322  {
1323  return _Get(0);
1324  }
1325 
1332 
1333  const_pointer operator->() const
1334  {
1335  return (&**this);
1336  }
1337 
1341 
1342  const_reference operator[](size_t _Pos) const
1343  {
1344  return _Get(_Pos);
1345  }
1346 
1353 
1354  _Myt& operator++()
1355  {
1356  ++_M_index;
1357  return (*this);
1358  }
1359 
1366 
1367  _Myt operator++(int)
1368  {
1369  _Myt _Tmp = *this;
1370  ++*this;
1371  return (_Tmp);
1372  }
1373 
1374 private:
1375 
1376  // Get the element at the given offset.
1377  const_reference _Get(size_t _Pos) const
1378  {
1379  size_t _Index = _M_index + _Pos;
1380  if (_Index >= _M_array._Size())
1381  {
1382  return _M_sentinel;
1383  }
1384 
1385  return _M_array[_Index];
1386  }
1387 
1388  // Array to hold the snapshot of the link registry
1390 
1391  // Pointer to the underlying container (network link registry)
1392  _MyContainer * _M_pNetwork_link;
1393 
1394  // Current index
1395  size_t _M_index;
1396 
1397  // Sentinel value to return on bounds overflow
1398  _EType _M_sentinel;
1399 };
1400 
1417 
1418 template<class _LinkRegistry>
1419 class source_link_manager
1420 {
1421 public:
1422 
1426 
1427  typedef _LinkRegistry type;
1428 
1432 
1433  typedef typename _LinkRegistry::type _Block;
1434 
1438 
1439  typedef std::function<void(_Block *, bool)> _Callback_method;
1440 
1444 
1445  typedef _Block * _EType;
1446 
1451 
1452  typedef _EType const& const_reference;
1453 
1457 
1458  typedef _EType const* const_pointer;
1459 
1460  // Iterator
1461  friend class _Source_link_iterator<_LinkRegistry>;
1462 
1467 
1469 
1473 
1474  typedef ::Concurrency::details::_ReentrantPPLLock _LockType;
1475 
1479 
1481 
1485 
1487  {
1488  }
1489 
1493 
1495  {
1497  }
1498 
1505 
1507  {
1508  _M_pLinkedTarget = _PTarget;
1509  }
1510 
1518 
1519  void set_bound(size_t _MaxLinks)
1520  {
1521  _M_links.set_bound(_MaxLinks);
1522  }
1523 
1530 
1531  void add(_EType _Link)
1532  {
1533  if (_Link == NULL)
1534  {
1535  return;
1536  }
1537 
1538  {
1539  _LockHolder _Lock(_M_lock);
1540  _M_links.add(_Link);
1541 
1542  // We need to add the _Link first and then invoke the
1543  // callback because _Add could throw.
1544 
1545  // As soon as the above lock is released, remove would
1546  // find the link that was added and could unlink it before
1547  // we are able to invoke the notification below. Keeping an
1548  // active iterator would prevent that from happening.
1549  _M_iteratorCount++;
1550  }
1551 
1552  // Acquire a reference on this link by the target
1553  _Link->acquire_ref(_M_pLinkedTarget);
1554 
1555  // Release the active iterator
1556  release();
1557  }
1558 
1568 
1569  bool remove(_EType _Link)
1570  {
1571  bool _Removed = false;
1572  _EType _RemovedLink = NULL;
1574 
1575  if (_Link == NULL)
1576  {
1577  return false;
1578  }
1579 
1580  {
1581  _LockHolder _Lock(_M_lock);
1582  _Removed = _M_links.remove(_Link);
1583 
1584  if (!_Removed)
1585  {
1586  // No change was made
1587  return _Removed;
1588  }
1589 
1590  if (_M_iteratorCount == 0)
1591  {
1592  // Set the removed link to indicate that
1593  // notification callback needs to be invoked.
1594  _RemovedLink = _Link;
1595  }
1596  else
1597  {
1598  // The iterator will complete the pending operation
1600  }
1601  }
1602 
1603  // NOTE: touching "this" pointer is dangerous as soon as the above lock is released
1604 
1605  // Release the reference for this link
1606  if (_RemovedLink != NULL)
1607  {
1608  _RemovedLink->release_ref(_LinkedTarget);
1609  }
1610 
1611  return _Removed;
1612  }
1613 
1617 
1618  void reference()
1619  {
1620  _LockHolder _Lock(_M_lock);
1621  _M_iteratorCount++;
1622  }
1623 
1627 
1628  void release()
1629  {
1632 
1633  {
1634  _LockHolder _Lock(_M_lock);
1636  _M_iteratorCount--;
1637 
1638  if (_M_iteratorCount == 0)
1639  {
1640  if (_M_pendingRemove._Size() > 0)
1641  {
1642  // Snap the pending remove list with the lock held
1643  _M_pendingRemove._Swap(_LinksToRemove);
1644  }
1645  }
1646  }
1647 
1648  // NOTE: touching "this" pointer is dangerous as soon as the above lock is released
1649 
1650  // Release the references
1651  size_t _Size = _LinksToRemove._Size();
1652 
1653  for (size_t _I=0; _I < _Size; _I++)
1654  {
1655  _LinksToRemove[_I]->release_ref(_LinkedTarget);
1656  }
1657  }
1658 
1669 
1670  bool contains(_EType _Link)
1671  {
1672  _LockHolder _Lock(_M_lock);
1673  return _M_links.contains(_Link);
1674  }
1675 
1682 
1683  size_t count()
1684  {
1685  _LockHolder _Lock(_M_lock);
1686  return _M_links.count();
1687  }
1688 
1689 
1699 
1700  iterator begin()
1701  {
1702  return (iterator(this, 0));
1703  }
1704 
1705 private:
1706 
1707  // Called by the iterator. This routine takes a snapshot of the links
1708  // in the registry and copies it to the array provided.
1710  {
1711  _LockHolder _Lock(_M_lock);
1712  _M_iteratorCount++;
1713 
1714  for(auto _Link = _M_links.begin(); *_Link != NULL; ++_Link)
1715  {
1716  _Array._Push_back(*_Link);
1717  }
1718  }
1719 
1720  // Internal lock used for synchronization
1721  _LockType _M_lock;
1722 
1723  // Count to indicate that an iterator is active
1724  volatile long _M_iteratorCount;
1725 
1726  // A vector of all pending link remove operations
1728 
1729  // Underlying link registry
1730  _LinkRegistry _M_links;
1731 
1732  // Target block holding this source link manager
1734 };
1735 
1739 
1741 {
1745 
1750 
1755 
1760 
1762 };
1763 
1774 
1775 template<class _Type>
1777 {
1778  friend class ::Concurrency::details::_Queue<message<_Type>>;
1779 
1780 public:
1792 
1793  message(_Type const &_P) : payload(_P), _M_pNext(NULL), _M_refCount(0) { }
1794 
1809 
1810  message(_Type const &_P, runtime_object_identity _Id)
1811  : ::Concurrency::details::_Runtime_object(_Id), payload(_P), _M_pNext(NULL), _M_refCount(0)
1812  {
1813  }
1814 
1826 
1827  message(message const & _Msg) : payload(_Msg.payload), _M_pNext(NULL), _M_refCount(0) { }
1828 
1839 
1840  message(_In_ message const * _Msg) : payload((_Msg == NULL) ? NULL : _Msg->payload), _M_pNext(NULL), _M_refCount(0)
1841  {
1842  if (_Msg == NULL)
1843  {
1844  throw std::invalid_argument("_Msg");
1845  }
1846  }
1847 
1851 
1852  virtual ~message() { }
1853 
1860 
1861  runtime_object_identity msg_id() const
1862  {
1863  return _M_id;
1864  }
1865 
1869 
1870  _Type const payload;
1871 
1879 
1880  long add_ref()
1881  {
1883  }
1884 
1892 
1893  long remove_ref()
1894  {
1896  }
1897 
1901 
1902  typedef typename _Type type;
1903 
1904 private:
1905  // The intrusive next pointer used by blocks that need
1906  // to chain messages it's holding together
1908 
1909  // Avoid warnings about not generating assignment operators.
1910  message<_Type> const &operator =(message<_Type> const &);
1911 
1912  // A reference count for the message
1913  volatile long _M_refCount;
1914 };
1915 
1916 //**************************************************************************
1917 // Message processor:
1918 //**************************************************************************
1919 
1928 
1929 template<class _Type>
1931 {
1932 public:
1936 
1937  typedef typename _Type type;
1938 
1948 
1949  virtual void async_send(_Inout_opt_ message<_Type> * _Msg) = 0;
1950 
1960 
1961  virtual void sync_send(_Inout_opt_ message<_Type> * _Msg) = 0;
1962 
1969 
1970  virtual void wait() = 0;
1971 
1972 protected:
1973 
1982 
1983  virtual void process_incoming_message() = 0;
1984 
1992 
1993  static void __cdecl _Process_incoming_message_wrapper(void * _Data)
1994  {
1995  message_processor<_Type> * _PMessageProcessor = (message_processor<_Type> *) _Data;
1996  _PMessageProcessor->process_incoming_message();
1997  }
1998 };
1999 
2007 
2008 template<class _Type>
2010 {
2011 public:
2015 
2016  typedef std::function<void(message<_Type> *)> _Handler_method;
2017 
2021 
2022  typedef std::function<void(void)> _Propagator_method;
2023 
2027 
2028  typedef _Type type;
2029 
2037 
2039  _M_queuedDataCount(0),
2040  _M_stopProcessing(1),
2041  _M_lwtCount(0),
2044  _M_handler(nullptr),
2045  _M_processor(nullptr),
2046  _M_propagator(nullptr)
2047  {
2048  }
2049 
2056 
2058  {
2059  wait();
2060  }
2061 
2077 
2078  void initialize(_Inout_opt_ Scheduler * _PScheduler, _Inout_opt_ ScheduleGroup * _PScheduleGroup, _Handler_method const& _Handler)
2079  {
2080  _M_pScheduler = _PScheduler;
2081  _M_pScheduleGroup = _PScheduleGroup;
2082  _M_handler = _Handler;
2083  _M_stopProcessing = 0;
2084  }
2085 
2095  virtual void initialize_batched_processing(_Handler_method const& _Processor, _Propagator_method const& _Propagator)
2096  {
2097  _M_processor = _Processor;
2098  _M_propagator = _Propagator;
2099  }
2100 
2108 
2109  virtual void sync_send(_Inout_opt_ message<_Type> * _Msg)
2110  {
2111  if (_M_handler == NULL)
2112  {
2113  throw invalid_operation("sync_send called without registering a callback");
2114  }
2115 
2116  _Sync_send_helper(_Msg);
2117  }
2118 
2126 
2128  {
2129  if (_M_handler == NULL)
2130  {
2131  throw invalid_operation("async_send called without registering a callback");
2132  }
2133 
2134  //
2135  // If there is a message to send, enqueue it in the processing queue.
2136  // async_send can be sent a NULL message if the block wishes to reprocess
2137  // the messages that are in its queue. For example, an unbounded_buffer
2138  // that has its head node released after reservation.
2139  //
2140  if (_Msg != NULL)
2141  {
2142  _M_queuedMessages.push(_Msg);
2143  }
2144 
2146  {
2147  // Indicate that an LWT is in progress. This will cause the
2148  // destructor to block.
2150 
2151  if (_M_stopProcessing == 0)
2152  {
2154 
2156 
2158 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
2159  if (_M_pScheduleGroup != NULL)
2160  {
2161  _M_pScheduleGroup->ScheduleTask(_Proc, this);
2162  }
2163  else if (_M_pScheduler != NULL)
2164  {
2165  _M_pScheduler->ScheduleTask(_Proc, this);
2166  }
2167  else
2168  {
2169 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
2171 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
2172  }
2173 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
2174 
2175  // The LWT will decrement _M_lwtCount.
2176  return;
2177  }
2178 
2179  // If we get here then no task was scheduled. Decrement LWT count to reflect this fact
2181  }
2182  }
2183 
2188 
2189  virtual void wait()
2190  {
2191  // Cease processing of any new messages
2193 
2194  // This spin makes sure all previously initiated message processings
2195  // will still process correctly. As soon as this count reaches zero, we can
2196  // proceed with the message block destructor.
2198  while(_M_lwtCount != 0)
2199  {
2200  spinWait._SpinOnce();
2201  }
2202 
2203  // Synchronize with sync_send
2204  {
2205  _NR_lock _Lock(_M_asyncSendLock);
2207  }
2208 
2209  }
2210 
2211 protected:
2212 
2217 
2219  {
2223 
2224  // Indicate that an LWT completed
2226 
2227  // Do not access any members here. If the count goes to
2228  // 0 as a result of the above decrement, the object
2229  // could be immediately deleted.
2230  }
2231 
2232  private:
2233 
2235  {
2236  message<_Type> * _Msg = NULL;
2237  while (_M_queuedMessages.try_pop(_Msg))
2238  {
2239  delete _Msg;
2240  }
2241  }
2242 
2244  {
2245  _NR_lock _Lock(_M_asyncSendLock);
2246 
2247  // Message block destructors sets the _M_stopProcessing flag to stop
2248  // processing any more messages. This is required to guarantee
2249  // that the destructor's wait_for_async_sends will complete
2250  if (_M_stopProcessing == 0)
2251  {
2252  if (_M_queuedDataCount > 0)
2253  {
2254  long _Count = _InterlockedExchange((volatile long *) &_M_queuedDataCount, 0);
2255  _Invoke_handler(_Count);
2256  }
2257 
2258  _Invoke_handler(_Msg);
2259  }
2260  else
2261  {
2262  // Destructor is running. Do not process the message
2263  // Delete the msg, if any.
2264  if (_Msg != NULL)
2265  {
2266  delete _Msg;
2267  }
2268  }
2269 
2270  }
2271 
2272  // Helper function to dequeue and process messages to any targets
2274  {
2275  _NR_lock _Lock(_M_asyncSendLock);
2276 
2277  long _Messages_processed = 0;
2278 
2279  // Do batched processing of messages
2280  // Read off the number of messages to process in this iteration by snapping a count
2281  volatile long _Count = _M_queuedDataCount;
2282  bool _StopProcessing = false;
2283 
2284  // This count could be 0 if there was both a synchronous and asynchronous
2285  // send occurring. One of them could have sent all of the messages for the other
2286  while (_Count > 0)
2287  {
2288  // Process _Count number of messages
2289  _Invoke_handler(_Count);
2290  _Messages_processed += _Count;
2291 
2292  // Subtract the count and see if there are new things to process
2293  volatile long _Orig = _InterlockedExchangeAdd((volatile long *) &_M_queuedDataCount, -_Count);
2294  _CONCRT_ASSERT(_Orig >= _Count);
2295  if (_Orig == _Count)
2296  {
2297  // Because _Count did not change, we processed everything there is to process
2298  break;
2299  }
2300 
2301  if (_StopProcessing)
2302  {
2303  break;
2304  }
2305 
2306  // After reading the flag process the currently queued messages
2307  // Any messages received after we observe this flag (to be set) will not
2308  // be processed.
2309  _StopProcessing = (_M_stopProcessing == 0) ? false : true;
2310 
2311  // Snap the count and try to process more
2312  _Count = _M_queuedDataCount;
2313  }
2314 
2315  return _Messages_processed;
2316  }
2317 
2318  // Invoke the handler in the message block for the given
2319  // count
2321  {
2322  // Process _Count number of messages
2323  for(int _I = 0; _I < _Count; _I++)
2324  {
2325  message<_Type> * _Msg = NULL;
2326  _M_queuedMessages.try_pop(_Msg);
2327  if (_M_processor == NULL)
2328  {
2329  // If a processor function does not exist, the message processor is using single
2330  // message processing rather than batched processing. There should also be no
2331  // propagator function defined in this case.
2333  _M_handler(_Msg);
2334  }
2335  else
2336  {
2337  // Use the batched message processing function
2338  _M_processor(_Msg);
2339  }
2340  }
2341 
2342  // Call the handler which propagates the message(s)
2343  if (_M_propagator != NULL)
2344  {
2345  _M_propagator();
2346  }
2347  }
2348 
2349  // Invoke the message block handler for the given message
2351  {
2352  if (_M_processor == NULL)
2353  {
2354  // If a processor function does not exist, the message processor is using single
2355  // message processing rather than batched processing. There should also be no
2356  // propagator function defined in this case.
2358  _M_handler(_Msg);
2359  }
2360  else
2361  {
2362  // Use the batched message processing function
2363  _M_processor(_Msg);
2364 
2365  // Call the handler which propagates the message(s)
2366  if (_M_propagator != NULL)
2367  {
2368  _M_propagator();
2369  }
2370  }
2371  }
2372 
2373  private:
2377 
2379 
2383 
2385 
2390 
2391  volatile long _M_queuedDataCount;
2392 
2396 
2397  Scheduler * _M_pScheduler;
2398 
2402 
2403  ScheduleGroup * _M_pScheduleGroup;
2404 
2409 
2410  volatile long _M_stopProcessing;
2411 
2415 
2416  volatile long _M_lwtCount;
2417 
2421 
2423 
2427 
2429 
2433 
2434  _Propagator_method _M_propagator;
2435 };
2436 
2448 
2449 template<class _Type>
2450 class ITarget
2451 {
2452  //
2453  // ISource<T> is a friend class because calls to Source->link_target()
2454  // and Source->unlink_target() need to call their respective
2455  // Target->link_source() and Target->unlink_source() on the block they are
2456  // linking/unlinking. Those functions are private here because we don't
2457  // want users calling link_source() or unlink_source() directly. link_source/
2458  // unlink_source don't call respective link_target/unlink_target because an
2459  // infinite loop would occur.
2460  //
2461  friend class ISource<_Type>;
2462 
2463 public:
2467 
2468  virtual ~ITarget() {}
2469 
2470  // It is important that calls to propagate do *not* take the same lock on an
2471  // internal message structure that is used by Consume and the LWT. Doing so could
2472  // result in a deadlock with the Consume call.
2473 
2492 
2493  virtual message_status propagate(_Inout_opt_ message<_Type> * _PMessage, _Inout_opt_ ISource<_Type> * _PSource) = 0;
2494 
2516 
2517  virtual message_status send(_Inout_ message<_Type> * _PMessage, _Inout_ ISource<_Type> * _PSource) = 0;
2518 
2529 
2531  {
2532  return false;
2533  }
2534 
2538 
2539  typedef typename _Type type;
2540 
2545 
2546  typedef std::function<bool(_Type const&)> filter_method;
2547 
2548 protected:
2549 
2561 
2562  virtual void link_source(_Inout_ ISource<_Type> * _PSource) = 0;
2563 
2575 
2576  virtual void unlink_source(_Inout_ ISource<_Type> * _PSource) = 0;
2577 
2581 
2582  virtual void unlink_sources() = 0;
2583 };
2584 
2596 
2597 template<class _Type>
2598 class ISource
2599 {
2600 public:
2604 
2605  virtual ~ISource() {}
2606 
2613 
2614  virtual void link_target(_Inout_ ITarget<_Type> * _PTarget) = 0;
2615 
2623 
2624  virtual void unlink_target(_Inout_ ITarget<_Type> * _PTarget) = 0;
2625 
2630 
2631  virtual void unlink_targets() = 0;
2632 
2651 
2652  virtual message<_Type> * accept(runtime_object_identity _MsgId, _Inout_ ITarget<_Type> * _PTarget) = 0;
2653 
2672 
2673  virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget<_Type> * _PTarget) = 0;
2674 
2692 
2693  virtual message<_Type> * consume(runtime_object_identity _MsgId, _Inout_ ITarget<_Type> * _PTarget) = 0;
2694 
2704 
2705  virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget<_Type> * _PTarget) = 0;
2706 
2717 
2718  virtual void acquire_ref(_Inout_ ITarget<_Type> * _PTarget) = 0;
2719 
2730 
2731  virtual void release_ref(_Inout_ ITarget<_Type> * _PTarget) = 0;
2732 
2736 
2737  typedef typename _Type source_type;
2738 
2739 protected:
2753 
2755  {
2756  _PLinkFrom->link_source(this);
2757  }
2758 
2772 
2774  {
2775  _PUnlinkFrom->unlink_source(this);
2776  }
2777 };
2778 
2779 //**************************************************************************
2780 // Direct Messaging APIs:
2781 //**************************************************************************
2782 
2806 
2807 template <class _Type>
2808 _Type _Receive_impl(ISource<_Type> * _Src, unsigned int _Timeout, typename ITarget<_Type>::filter_method const* _Filter_proc)
2809 {
2810  // The Blocking Recipient messaging block class is internal to the receive function
2811  class _Blocking_recipient : public ITarget<_Type>
2812  {
2813  public:
2814  // Create an Blocking Recipient
2815  _Blocking_recipient(ISource<_Type> * _PSource,
2816  unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE) :
2817  _M_pFilter(NULL), _M_pConnectedTo(NULL), _M_pMessage(NULL), _M_fState(_NotInitialized), _M_timeout(_Timeout)
2818  {
2819  _Connect(_PSource);
2820  }
2821 
2822  // Create an Blocking Recipient
2823  _Blocking_recipient(ISource<_Type> * _PSource,
2824  filter_method const& _Filter,
2825  unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE) :
2826  _M_pFilter(NULL), _M_pConnectedTo(NULL), _M_pMessage(NULL), _M_fState(_NotInitialized), _M_timeout(_Timeout)
2827  {
2828  if (_Filter != NULL)
2829  {
2830  _M_pFilter = new filter_method(_Filter);
2831  }
2832 
2833  _Connect(_PSource);
2834  }
2835 
2836  // Cleans up any resources that may have been created by the BlockingRecipient.
2837  ~_Blocking_recipient()
2838  {
2839  _Disconnect();
2840 
2841  delete _M_pFilter;
2842  delete _M_pMessage;
2843  }
2844 
2845  // Gets the value of the message sent to this BlockingRecipient. Blocks by
2846  // spinning until a message has arrived.
2847  _Type _Value()
2848  {
2849  _Wait_for_message();
2850 
2851  return _M_pMessage->payload;
2852  }
2853 
2854  // The main propagation function for ITarget blocks. Called by a source
2855  // block, generally within an asynchronous task to send messages to its targets.
2856  virtual message_status propagate(message<_Type> * _PMessage, ISource<_Type> * _PSource)
2857  {
2858  // Throw exception if the message being propagated to this block is NULL
2859  if (_PMessage == NULL)
2860  {
2861  throw std::invalid_argument("_PMessage");
2862  }
2863 
2864  if (_PSource == NULL)
2865  {
2866  throw std::invalid_argument("_PSource");
2867  }
2868 
2869  // Reject if the recipient has already received a message
2870  if (_M_fState == _Initialized)
2871  {
2872  return declined;
2873  }
2874 
2875  // Reject if the message does not meet the filter requirements
2876  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
2877  {
2878  return declined;
2879  }
2880 
2881  // Accept the message
2882  _CONCRT_ASSERT(_PSource != NULL);
2883  _M_pMessage = _PSource->accept(_PMessage->msg_id(), this);
2884 
2885  if (_M_pMessage != NULL)
2886  {
2887  // Set the initialized flag on this block
2888  if (_InterlockedExchange(&_M_fState, _Initialized) == _Blocked)
2889  {
2890  _M_ev.set();
2891  }
2892 
2893  return accepted;
2894  }
2895 
2896  return missed;
2897  }
2898 
2899  // Synchronously sends a message to this block. When this function completes the message will
2900  // already have propagated into the block.
2901  virtual message_status send(message<_Type> * _PMessage, ISource<_Type> * _PSource)
2902  {
2903  if (_PMessage == NULL)
2904  {
2905  throw std::invalid_argument("_PMessage");
2906  }
2907 
2908  if (_PSource == NULL)
2909  {
2910  throw std::invalid_argument("_PSource");
2911  }
2912 
2913  // Only the connected source is allowed to send messages
2914  // to the blocking recipient. Decline messages without
2915  // a source.
2916 
2917  return declined;
2918  }
2919 
2920  private:
2921 
2922  // Link a source block
2923  virtual void link_source(ISource<_Type> * _PSrc)
2924  {
2925  _M_pConnectedTo = _PSrc;
2926  _PSrc->acquire_ref(this);
2927  }
2928 
2929  // Remove a source messaging block for this BlockingRecipient
2930  virtual void unlink_source(ISource<_Type> * _PSource)
2931  {
2932  if (_InterlockedCompareExchangePointer(reinterpret_cast<void *volatile *>(&_M_pConnectedTo), (void *)NULL, _PSource) == _PSource)
2933  {
2934  _PSource->release_ref(this);
2935  }
2936  }
2937 
2938  // Remove the source messaging block for this BlockingRecipient
2939  virtual void unlink_sources()
2940  {
2941  ISource<_Type> * _PSource = reinterpret_cast<ISource<_Type> *>(_InterlockedExchangePointer(reinterpret_cast<void *volatile *>(&_M_pConnectedTo), (void *)NULL));
2942  if (_PSource != NULL)
2943  {
2944  _PSource->unlink_target(this);
2945  _PSource->release_ref(this);
2946  }
2947  }
2948 
2949 
2950  // Connect the blocking recipient to the source
2951  void _Connect(ISource<_Type> * _PSource)
2952  {
2953  if (_PSource == NULL)
2954  {
2955  throw std::invalid_argument("_PSource");
2956  }
2957 
2958  _PSource->link_target(this);
2959  }
2960 
2961  // Cleanup the connection to the blocking recipient's source. There is no need
2962  // to do anything about the associated context.
2963  void _Disconnect()
2964  {
2965  unlink_sources();
2966  }
2967 
2968  // Internal function used to block while waiting for a message to arrive
2969  // at this BlockingRecipient
2970  void _Wait_for_message()
2971  {
2972  bool _Timeout = false;
2973 
2974  // If we haven't received a message yet, cooperatively block.
2975  if (_InterlockedCompareExchange(&_M_fState, _Blocked, _NotInitialized) == _NotInitialized)
2976  {
2977  if (_M_ev.wait(_M_timeout) == COOPERATIVE_WAIT_TIMEOUT)
2978  {
2979  _Timeout = true;
2980  }
2981  }
2982 
2983  // Unlinking from our source guarantees that there are no threads in propagate
2984  _Disconnect();
2985 
2986  if (_M_fState != _Initialized)
2987  {
2988  // We had to have timed out if we came out of the wait
2989  // without being initialized.
2990  _CONCRT_ASSERT(_Timeout);
2991 
2992  throw operation_timed_out();
2993  }
2994  }
2995 
2996  // States for this block
2997  enum
2998  {
2999  _NotInitialized,
3000  _Blocked,
3001  _Initialized
3002  };
3003 
3004  volatile long _M_fState;
3005 
3006  // The source messaging block connected to this Recipient
3007  ISource<_Type> * _M_pConnectedTo;
3008 
3009  // The message that was received
3010  message<_Type> * volatile _M_pMessage;
3011 
3012  // The timeout.
3013  unsigned int _M_timeout;
3014 
3015  // The event we wait upon
3016  event _M_ev;
3017 
3018  // The filter that is called on this block before accepting a message
3019  filter_method * _M_pFilter;
3020  };
3021 
3022  if (_Filter_proc != NULL)
3023  {
3024  _Blocking_recipient _Recipient(_Src, *_Filter_proc, _Timeout);
3025  return _Recipient._Value();
3026  }
3027  else
3028  {
3029  _Blocking_recipient _Recipient(_Src, _Timeout);
3030  return _Recipient._Value();
3031  }
3032 }
3033 
3061 
3062 template <class _Type>
3063 _Type receive(_Inout_ ISource<_Type> * _Src, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE)
3064 {
3065  return _Receive_impl(_Src, _Timeout, NULL);
3066 }
3067 
3098 
3099 template <class _Type>
3100 _Type receive(_Inout_ ISource<_Type> * _Src, typename ITarget<_Type>::filter_method const& _Filter_proc, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE)
3101 {
3102  return _Receive_impl(_Src, _Timeout, &_Filter_proc);
3103 }
3104 
3132 
3133 template <class _Type>
3134 _Type receive(ISource<_Type> &_Src, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE)
3135 {
3136  return _Receive_impl(&_Src, _Timeout, NULL);
3137 }
3138 
3169 
3170 template <class _Type>
3171 _Type receive(ISource<_Type> &_Src, typename ITarget<_Type>::filter_method const& _Filter_proc, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE)
3172 {
3173  return _Receive_impl(&_Src, _Timeout, &_Filter_proc);
3174 }
3175 
3197 
3198 template <class _Type>
3199 bool _Try_receive_impl(ISource<_Type> * _Src, _Type & _value, typename ITarget<_Type>::filter_method const * _Filter_proc)
3200 {
3201  // The Immediate Recipient messaging block class is internal to the receive function
3202  class _Immediate_recipient : public ITarget<_Type>
3203  {
3204  public:
3205  // Create an Immediate Recipient
3206  _Immediate_recipient(ISource<_Type> * _PSource) :
3207  _M_pFilter(NULL), _M_pConnectedTo(NULL), _M_pMessage(NULL), _M_isInitialized(0)
3208  {
3209  _Connect(_PSource);
3210  }
3211 
3212  // Create an Immediate Recipient
3213  _Immediate_recipient(ISource<_Type> * _PSource,
3214  filter_method const& _Filter) :
3215  _M_pFilter(NULL), _M_pConnectedTo(NULL), _M_pMessage(NULL), _M_isInitialized(0)
3216  {
3217  if (_Filter != NULL)
3218  {
3219  _M_pFilter = new filter_method(_Filter);
3220  }
3221 
3222  _Connect(_PSource);
3223  }
3224 
3225  // Cleans up any resources that may have been created by the ImmediateRecipient.
3226  ~_Immediate_recipient()
3227  {
3228  _Disconnect();
3229 
3230  delete _M_pFilter;
3231  delete _M_pMessage;
3232  }
3233 
3234  // Gets the value of the message sent to this ImmediateRecipient.
3235  bool _Value(_Type & _value)
3236  {
3237  // Unlinking from our source guarantees that there are no threads in propagate
3238  _Disconnect();
3239 
3240  if (_M_pMessage != NULL)
3241  {
3242  _value = _M_pMessage->payload;
3243  return true;
3244  }
3245 
3246  return false;
3247  }
3248 
3249  // The main propagation function for ITarget blocks. Called by a source
3250  // block, generally within an asynchronous task to send messages to its targets.
3251  virtual message_status propagate(message<_Type> * _PMessage, ISource<_Type> * _PSource)
3252  {
3253  message_status _Result = accepted;
3254 
3255  // Throw exception if the message being propagated to this block is NULL
3256  if (_PMessage == NULL)
3257  {
3258  throw std::invalid_argument("_PMessage");
3259  }
3260 
3261  if (_PSource == NULL)
3262  {
3263  throw std::invalid_argument("_PSource");
3264  }
3265 
3266  // Reject if the recipient has already received a message
3267  if (_M_isInitialized == 1)
3268  {
3269  return declined;
3270  }
3271 
3272  // Reject if the message does not meet the filter requirements
3273  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
3274  {
3275  return declined;
3276  }
3277 
3278  // Accept the message
3279  _CONCRT_ASSERT(_PSource != NULL);
3280  _M_pMessage = _PSource->accept(_PMessage->msg_id(), this);
3281 
3282  // Set the initialized flag on this block
3283 
3284  if (_M_pMessage != NULL)
3285  {
3286  // Fence to ensure that the above update to _M_pMessage is visible
3287  _InterlockedExchange(&_M_isInitialized, 1);
3288  _Result = accepted;
3289  }
3290  else
3291  {
3292  _Result = missed;
3293  }
3294 
3295  return _Result;
3296  }
3297 
3298 
3299  // Synchronously sends a message to this block. When this function completes the message will
3300  // already have propagated into the block.
3301  virtual message_status send(message<_Type> * _PMessage, ISource<_Type> * _PSource)
3302  {
3303  if (_PMessage == NULL)
3304  {
3305  throw std::invalid_argument("_PMessage");
3306  }
3307 
3308  if (_PSource == NULL)
3309  {
3310  throw std::invalid_argument("_PSource");
3311  }
3312 
3313  // Only the connected source is allowed to send messages
3314  // to the blocking recipient. Decline messages without
3315  // a source.
3316 
3317  return declined;
3318  }
3319 
3320  private:
3321 
3322  // Add a source messaging block
3323  virtual void link_source(ISource<_Type> * _PSrc)
3324  {
3325  _M_pConnectedTo = _PSrc;
3326  _PSrc->acquire_ref(this);
3327  }
3328 
3329  // Remove a source messaging block for this BlockingRecipient
3330  virtual void unlink_source(ISource<_Type> * _PSource)
3331  {
3332  if (_InterlockedCompareExchangePointer(reinterpret_cast<void *volatile *>(&_M_pConnectedTo), (void *)NULL, _PSource) == _PSource)
3333  {
3334  _PSource->release_ref(this);
3335  }
3336  }
3337 
3338  // Remove the source messaging block for this BlockingRecipient
3339  virtual void unlink_sources()
3340  {
3341  ISource<_Type> * _PSource = reinterpret_cast<ISource<_Type> *>(_InterlockedExchangePointer(reinterpret_cast<void *volatile *>(&_M_pConnectedTo), (void *)NULL));
3342  if (_PSource != NULL)
3343  {
3344  _PSource->unlink_target(this);
3345  _PSource->release_ref(this);
3346  }
3347  }
3348 
3349  // Connect to a source block
3350  void _Connect(ISource<_Type> * _PSource)
3351  {
3352  if (_PSource == NULL)
3353  {
3354  throw std::invalid_argument("_PSource");
3355  }
3356 
3357  _CONCRT_ASSERT(_M_isInitialized == 0);
3358 
3359  _PSource->link_target(this);
3360  }
3361 
3362  //
3363  // Cleanup the connection to the trigger's source. There is no need
3364  // to do anything about the associated context.
3365  //
3366  void _Disconnect()
3367  {
3368  unlink_sources();
3369  }
3370 
3371  // The source messaging block connected to this Recipient
3372  ISource<_Type> * _M_pConnectedTo;
3373 
3374  // The message that was received
3375  message<_Type> * volatile _M_pMessage;
3376 
3377  // A flag for whether or not this block has been initialized with a value
3378  volatile long _M_isInitialized;
3379 
3380  // The filter that is called on this block before accepting a message
3381  filter_method * _M_pFilter;
3382  };
3383 
3384  if (_Filter_proc != NULL)
3385  {
3386  _Immediate_recipient _Recipient(_Src, *_Filter_proc);
3387  return _Recipient._Value(_value);
3388  }
3389  else
3390  {
3391  _Immediate_recipient _Recipient(_Src);
3392  return _Recipient._Value(_value);
3393  }
3394 }
3395 
3419 
3420 template <class _Type>
3421 bool try_receive(_Inout_ ISource<_Type> * _Src, _Type & _value)
3422 {
3423  return _Try_receive_impl(_Src, _value, NULL);
3424 }
3425 
3452 
3453 template <class _Type>
3454 bool try_receive(_Inout_ ISource<_Type> * _Src, _Type & _value, typename ITarget<_Type>::filter_method const& _Filter_proc)
3455 {
3456  return _Try_receive_impl(_Src, _value, &_Filter_proc);
3457 }
3458 
3482 
3483 template <class _Type>
3484 bool try_receive(ISource<_Type> & _Src, _Type & _value)
3485 {
3486  return _Try_receive_impl(&_Src, _value, NULL);
3487 }
3488 
3515 
3516 template <class _Type>
3517 bool try_receive(ISource<_Type> & _Src, _Type & _value, typename ITarget<_Type>::filter_method const& _Filter_proc)
3518 {
3519  return _Try_receive_impl(&_Src, _value, &_Filter_proc);
3520 }
3521 
3522 namespace details
3523 {
3524  //**************************************************************************
3525  // Supporting blocks for send and asend
3526  //**************************************************************************
3527 
3528  // Originator block that pushes messages to a target
3529  template <class _Type>
3530  class _AnonymousOriginator : public ISource<_Type>
3531  {
3532  public:
3533 
3535 
3536  // Create an Originator
3538  {
3539  }
3540 
3541  // Cleans up any resources that may have been created by the Originator.
3543  {
3544  delete _M_pMessage;
3545  }
3546 
3547  // Removes a target messaging block for this Originator
3548  virtual void unlink_target(ITarget<_Type> * _PTarget)
3549  {
3550  throw invalid_operation("unlink_target is not supported on _AnonymousOriginator");
3551  }
3552 
3553  // Removes the target messaging block from this Originator
3554  virtual void unlink_targets()
3555  {
3556  throw invalid_operation("unlink_targets is not supported on _AnonymousOriginator");
3557  }
3558 
3559  // Accept on this Originator is called by a target to take ownership of a
3560  // propagated message
3561  virtual message<_Type> * accept(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3562  {
3563  if (_PTarget != _M_pTarget)
3564  {
3565  return NULL;
3566  }
3567 
3568  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
3569  {
3570  return NULL;
3571  }
3572 
3573  // The IDs match. Actually transfer ownership of the message and
3574  // unlink away from the target
3575  message<_Type> * _Result = _M_pMessage;
3576 
3577  // The ownership of this message has changed. Set the internal pointer to NULL
3578  // so it won't be deleted in the destructor
3579  _M_pMessage = NULL;
3580 
3581  return _Result;
3582  }
3583 
3584  // Reserve shall not be called by blocks that supports push
3585  virtual bool reserve(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3586  {
3587  throw invalid_operation("reserve is not supported on _AnonymousOriginator");
3588  }
3589 
3590  // Consume shall not be called by blocks that supports push
3591  virtual message<_Type> * consume(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3592  {
3593  throw invalid_operation("consume is not supported on _AnonymousOriginator");
3594  }
3595 
3596  // Release needs to be defined for ISource blocks, but Originator doesn't need to
3597  // do anything for reservation release because there can only be one target block to read
3598  // the data at a later time.
3599  virtual void release(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3600  {
3601  throw invalid_operation("release is not supported on _AnonymousOriginator");
3602  }
3603 
3605  {
3606  throw invalid_operation("acquire_ref is not supported on _AnonymousOriginator");
3607  }
3608 
3610  {
3611  throw invalid_operation("release_ref is not supported on _AnonymousOriginator");
3612  }
3613 
3614  private:
3615  friend class _Originator;
3616 
3617  // Send the given value to the target
3618  bool _internal_send(ITarget<_Type> * _PTarget, _Type const & _Value)
3619  {
3620  _M_pTarget = _PTarget;
3621 
3623  _CONCRT_ASSERT(_M_pTarget->supports_anonymous_source());
3624 
3625  // Create the message
3626  message_status _Status = declined;
3627  message<_Type> * _Msg = new message<_Type>(_Value);
3628 
3630  _M_pMessage = _Msg;
3631 
3632  // Send the message
3633  _Status = _M_pTarget->send(_M_pMessage, this);
3634 
3635  // If the message is declined, the destructor will
3636  // delete the message
3637 
3638  // status should not be postponed.
3639  _CONCRT_ASSERT(_Status != postponed);
3640  return (_Status == accepted);
3641  }
3642 
3643  bool _internal_asend(ITarget<_Type> * _PTarget, _Type const & _Value)
3644  {
3645  _M_pTarget = _PTarget;
3646 
3648  _CONCRT_ASSERT(_M_pTarget->supports_anonymous_source());
3649 
3650  // Create the message
3651  message_status _Status = declined;
3652  message<_Type> * _Msg = new message<_Type>(_Value);
3653 
3655  _M_pMessage = _Msg;
3656 
3657  // Send the message
3658  _Status = _M_pTarget->propagate(_M_pMessage, this);
3659 
3660  // If the message is declined, the destructor will
3661  // delete the message
3662 
3663  // status should not be postponed.
3664  if (_Status == postponed)
3665  {
3666  throw invalid_operation("Messages offered by _AnonymousOriginator shall not be postponed");
3667  }
3668 
3669  return (_Status == accepted);
3670  }
3671 
3672  // Add a target messaging block for this Originator
3673  virtual void link_target(ITarget<_Type> * _PTarget)
3674  {
3675  throw invalid_operation("link_target is not supported on _AnonymousOriginator");
3676  }
3677 
3678  // The message that will be propagated by the Originator
3680 
3681  // The single target for this block
3683  };
3684 
3685  // The Originator messaging block class is internal to the send function.
3686  template <class _Type>
3687  class _SyncOriginator : public ISource<_Type>
3688  {
3689  public:
3690 
3692 
3693  // Create an Originator
3695  _M_pMessage(NULL),
3698  {
3699  }
3700 
3701  // Cleans up any resources that may have been created by the Originator.
3703  {
3704  unlink_targets();
3705 
3706  _Wait_on_ref();
3707 
3708  delete _M_pMessage;
3709  }
3710 
3711  // Removes a target messaging block for this Originator
3712  virtual void unlink_target(ITarget<_Type> * _PTarget)
3713  {
3714  if (_PTarget == NULL)
3715  {
3716  throw std::invalid_argument("_PTarget");
3717  }
3718  {
3719  // Hold the lock to ensure that the target doesn't unlink while
3720  // propagation is in progress.
3721  _R_lock _Lock(_M_internalLock);
3722  if (_M_connectedTargets.remove(_PTarget))
3723  {
3724  _Invoke_unlink_source(_PTarget);
3725 
3726  // Indicate that the send is complete
3727  _Done(declined);
3728  }
3729  }
3730  }
3731 
3732  // Removes the target messaging block from this Originator
3733  virtual void unlink_targets()
3734  {
3735  // Hold the lock to ensure that the target doesn't unlink while
3736  // propagation is in progress.
3737  _R_lock _Lock(_M_internalLock);
3738 
3739  for (typename _Target_registry::iterator _Iter = _M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
3740  {
3741  ITarget<_Type> * _PTarget = *_Iter;
3742  if (_M_connectedTargets.remove(_PTarget))
3743  {
3744  _Invoke_unlink_source(_PTarget);
3745  }
3746  }
3747 
3748  // All targets should be unlinked
3750 
3751  // Indicate that the send is complete
3752  _Done(declined);
3753  }
3754 
3755  // Accept on this Originator is called by a target to take ownership of a
3756  // propagated message
3757  virtual message<_Type> * accept(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3758  {
3759  if (_PTarget == NULL)
3760  {
3761  return NULL;
3762  }
3763 
3764  if (!_M_connectedTargets.contains(_PTarget))
3765  {
3766  return NULL;
3767  }
3768 
3769  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
3770  {
3771  return NULL;
3772  }
3773 
3774  // The IDs match. Actually transfer ownership of the message and
3775  // unlink away from the target
3776  message<_Type> * _Result = _M_pMessage;
3777 
3778  // The ownership of this message has changed. Set the internal pointer to NULL
3779  // so it won't be deleted in the destructor
3780  _M_pMessage = NULL;
3781 
3782  // The message has been accepted/consumed, propagate indication that it has succeeded
3783  _Done(accepted);
3784 
3785  return _Result;
3786  }
3787 
3788  // Reserve needs to be defined for ISource blocks, but Originator doesn't need to
3789  // do anything for reservation because there can only be one target block to read
3790  // the data at a later time.
3791  virtual bool reserve(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3792  {
3793  if (_PTarget == NULL)
3794  {
3795  throw std::invalid_argument("_PTarget");
3796  }
3797 
3798  if (!_M_connectedTargets.contains(_PTarget))
3799  {
3800  return false;
3801  }
3802 
3803  if (_M_pMessage->msg_id() != _MsgId)
3804  {
3805  return false;
3806  }
3807 
3808  return true;
3809  }
3810 
3811  // Consume is called by a target messaging block to take ownership of a
3812  // previously reserved message.
3813  virtual message<_Type> * consume(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3814  {
3815  if (_PTarget == NULL)
3816  {
3817  throw std::invalid_argument("_PTarget");
3818  }
3819 
3820  if (!_M_connectedTargets.contains(_PTarget))
3821  {
3822  throw bad_target();
3823  }
3824 
3825  return accept(_MsgId, _PTarget);
3826  }
3827 
3828  // Release needs to be defined for ISource blocks, but Originator doesn't need to
3829  // do anything for reservation release because there can only be one target block to read
3830  // the data at a later time.
3831  virtual void release(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
3832  {
3833  if (_PTarget == NULL)
3834  {
3835  throw std::invalid_argument("_PTarget");
3836  }
3837 
3838  if (!_M_connectedTargets.contains(_PTarget))
3839  {
3840  throw bad_target();
3841  }
3842 
3843  if ((_M_pMessage == NULL) || (_M_pMessage->msg_id() != _MsgId))
3844  {
3845  throw message_not_found();
3846  }
3847 
3848  // If the previously reserved message is released, then propagate
3849  // declined to indicate that the message was not accepted.
3850  _Done(declined);
3851  }
3852 
3854  {
3856  }
3857 
3859  {
3861  }
3862 
3863  private:
3864 
3865  friend class _Originator;
3866 
3867  // Send the given value to the target
3868  bool _internal_send(ITarget<_Type> * _PTarget, _Type const & _Value)
3869  {
3870  // _send should only be called once.
3871  if (_PTarget == NULL)
3872  {
3873  throw std::invalid_argument("_PTarget");
3874  }
3875 
3876  message_status _Status = declined;
3877  message<_Type> * _Msg = new message<_Type>(_Value);
3878 
3879  {
3880  // Hold the lock to ensure that the target doesn't unlink while
3881  // propagation is in progress.
3882  _R_lock _Lock(_M_internalLock);
3883 
3884  // link to the target, create a message and send it
3885  link_target(_PTarget);
3886 
3888  _M_pMessage = _Msg;
3889 
3890  // Send the message synchronously to the target
3891  _Status = _PTarget->send(_M_pMessage, this);
3892  }
3893 
3894  if (_Status == postponed)
3895  {
3896  // If the target postponed the message, wait for it to
3897  // be accepted/declined.
3899 
3900  // Procure the final status
3901  _Status = _M_fStatus;
3902  }
3903 
3904  // status should not be postponed.
3905  _CONCRT_ASSERT(_Status != postponed);
3906 
3907  return (_Status == accepted);
3908  }
3909 
3910  // Add a target messaging block for this Originator
3911  virtual void link_target(ITarget<_Type> * _PTarget)
3912  {
3913  if (_PTarget == NULL)
3914  {
3915  throw std::invalid_argument("_PTarget");
3916  }
3917 
3918  _M_connectedTargets.add(_PTarget);
3919  _Invoke_link_source(_PTarget);
3920 
3921  // There should be no pending messages to propagate at this time.
3923  }
3924 
3925  // Wait for the status to reach one of the terminal
3926  // states (!= postponed)
3928  {
3929  // Wait for the event to be signalled
3932 
3933  }
3934 
3936  {
3938  while(_M_referenceCount != 0)
3939  {
3940  spinWait._SpinOnce();
3941  }
3942  }
3943 
3944  // Indicate that the send operation has completed
3945  void _Done(message_status _Status)
3946  {
3947  // postponed is not a done state
3948  _CONCRT_ASSERT(_Status != postponed);
3949 
3950  _M_fStatus = _Status;
3951  _M_ev.set();
3952  }
3953 
3954  // The message that will be propagated by the Originator
3956 
3957  // Event to indicate completion
3958  event _M_ev;
3959 
3960  // Final status of the send
3962 
3963  // A lock for modifying the buffer or the connected blocks
3965 
3966  // Connected targets
3967  _Target_registry _M_connectedTargets;
3968 
3969  volatile long _M_referenceCount;
3970  };
3971 
3972  // The Originator messaging block class is internal to the send function.
3973  template <class _Type>
3974  class _AsyncOriginator : public ISource<_Type>
3975  {
3976  public:
3977 
3979 
3980  // Cleans up any resources that may have been created by the AsyncOriginator.
3982  {
3983  unlink_targets();
3984 
3985  delete _M_pMessage;
3986  }
3987 
3988  // Removes a target messaging block for this AsyncOriginator
3989  virtual void unlink_target(ITarget<_Type> * _PTarget)
3990  {
3991  if (_PTarget == NULL)
3992  {
3993  throw std::invalid_argument("_PTarget");
3994  }
3995 
3996  bool _Unlinked = false;
3997  {
3998  // Hold the lock to ensure that the target doesn't unlink while
3999  // propagation is in progress.
4000  _R_lock _Lock(_M_internalLock);
4001 
4002  if (_M_connectedTargets.remove(_PTarget))
4003  {
4004  _Invoke_unlink_source(_PTarget);
4005  _Unlinked = true;
4006  }
4007  }
4008 
4009  // Release the lock before decrementing the refcount. Otherwise, the
4010  // lock release could corrupt memory.
4011  if (_Unlinked)
4012  {
4013  _Release_ref();
4014  }
4015  }
4016 
4017  // Removes the target messaging block from this AsyncOriginator
4018  virtual void unlink_targets()
4019  {
4020  bool _Unlinked = false;
4021  {
4022  // Hold the lock to ensure that the target doesn't unlink while
4023  // propagation is in progress.
4024  _R_lock _Lock(_M_internalLock);
4025 
4026  for (typename _Target_registry::iterator _Iter = _M_connectedTargets.begin();
4027  *_Iter != NULL;
4028  ++_Iter)
4029  {
4030  ITarget<_Type> * _PTarget = *_Iter;
4031  if (_M_connectedTargets.remove(_PTarget))
4032  {
4033  _Invoke_unlink_source(_PTarget);
4034  _Unlinked = true;
4035  }
4036 
4037  }
4038 
4039  // All targets should be unlinked
4041  }
4042 
4043  // Release the lock before decrementing the refcount. Otherwise, the
4044  // lock release could corrupt memory.
4045  if (_Unlinked)
4046  {
4047  _Release_ref();
4048  }
4049  }
4050 
4051  // Accept on this AsyncOriginator is called by a target to take ownership of a
4052  // propagated message. This can only be called from propagate.
4053  virtual message<_Type> * accept(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
4054  {
4055  if (_PTarget == NULL)
4056  {
4057  return NULL;
4058  }
4059 
4060  if (!_M_connectedTargets.contains(_PTarget))
4061  {
4062  return NULL;
4063  }
4064 
4065  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
4066  {
4067  return NULL;
4068  }
4069 
4070  //
4071  // If the IDs match, actually transfer ownership of the message.
4072  //
4073  message<_Type> * _Result = _M_pMessage;
4074  _M_pMessage = NULL;
4075 
4076  return _Result;
4077  }
4078 
4079  // Reserve needs to be defined for ISource blocks, but AsyncOriginator doesn't need to
4080  // do anything for reservation because there can only be one target block to read
4081  // the data at a later time.
4082  virtual bool reserve(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
4083  {
4084  if (_PTarget == NULL)
4085  {
4086  throw std::invalid_argument("_PTarget");
4087  }
4088 
4089  if (!_M_connectedTargets.contains(_PTarget))
4090  {
4091  return false;
4092  }
4093 
4094  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
4095  {
4096  return false;
4097  }
4098 
4099  return true;
4100  }
4101 
4102  // Consume is called by a target messaging block to take ownership of a
4103  // previously reserved message.
4104  virtual message<_Type> * consume(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
4105  {
4106  if (_PTarget == NULL)
4107  {
4108  throw std::invalid_argument("_PTarget");
4109  }
4110 
4111  if (!_M_connectedTargets.contains(_PTarget))
4112  {
4113  throw bad_target();
4114  }
4115 
4116  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
4117  {
4118  return NULL;
4119  }
4120 
4121  // The ownership of this message has changed. Set the internal pointer to NULL
4122  // so it won't be deleted in the destructor
4123 
4124  message<_Type> * _Result = _M_pMessage;
4125  _M_pMessage = NULL;
4126 
4127  // We are done. Unlink from the target. DO NOT TOUCH "this" pointer after unlink
4128  unlink_target(_PTarget);
4129 
4130  return _Result;
4131  }
4132 
4133  // Release needs to be defined for ISource blocks, but AsyncOriginator doesn't need to
4134  // do anything for reservation release because there can only be one target block to read
4135  // the data at a later time.
4136  virtual void release(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget)
4137  {
4138  if (_PTarget == NULL)
4139  {
4140  throw std::invalid_argument("_PTarget");
4141  }
4142 
4143  if (!_M_connectedTargets.contains(_PTarget))
4144  {
4145  throw bad_target();
4146  }
4147 
4148  if ((_M_pMessage == NULL) || (_M_pMessage->msg_id() != _MsgId))
4149  {
4150  throw message_not_found();
4151  }
4152 
4153  // We can be connected to only 1 target. Unlink from the target.
4154  // DO NOT TOUCH "this" pointer after unlink
4155  unlink_target(_PTarget);
4156  }
4157 
4159  {
4160  _Acquire_ref();
4161  }
4162 
4164  {
4165  _Release_ref();
4166  }
4167 
4168  private:
4169 
4170  friend class _Originator;
4171 
4172  // Create an AsyncOriginator (constructor is private to ensure that
4173  // it is allocated on the heap).
4175  _M_pMessage(NULL),
4176  _M_refcount(0)
4177  {
4178  }
4179 
4180  // Send the given value to the target
4181  bool _internal_send(ITarget<_Type> * _PTarget, _Type const & _Value)
4182  {
4183  // Keep a refcount so that this object doesn't get deleted if
4184  // the target decides to unlink before we release our lock
4185  _Acquire_ref();
4186 
4187  message_status _Status = declined;
4188  message<_Type> * _Msg = new message<_Type>(_Value);
4189 
4190  {
4191  // Hold the lock to ensure that the target doesn't unlink while
4192  // propagation is in progress.
4193  _R_lock _Lock(_M_internalLock);
4194 
4195  // link to the target, create a message and send it
4196  link_target(_PTarget);
4197 
4199  _M_pMessage = _Msg;
4200 
4201  _Status = _PTarget->propagate(_M_pMessage, this);
4202  }
4203 
4204  // If the status is anything other than postponed, unlink away
4205  // from the target and delete the AsyncOriginator.
4206  if (_Status != postponed)
4207  {
4208  unlink_target(_PTarget);
4209  }
4210 
4211  // Release the reference acquired above
4212  _Release_ref();
4213 
4214  return (_Status == accepted);
4215  }
4216 
4217  // Add a target messaging block for this AsyncOriginator
4218  virtual void link_target(ITarget<_Type> * _PTarget)
4219  {
4220  if (_PTarget == NULL)
4221  {
4222  throw std::invalid_argument("_PTarget");
4223  }
4224 
4225  // Acquire a reference that will be released by unlink_target
4226  _Acquire_ref();
4227  _M_connectedTargets.add(_PTarget);
4228  _Invoke_link_source(_PTarget);
4229 
4230  // There should be no pending messages to propagate at this time.
4232 
4233  }
4234 
4235  // Acquire a reference on the async originator object
4237  {
4239  }
4240 
4241  // Release the reference on the async originator object. The object
4242  // will be deleted when the reference count goes to 0.
4244  {
4247  {
4248  delete this;
4249  }
4250  }
4251 
4252  // The message that will be propagated by the AsyncOriginator
4254 
4255  // Reference count to manage object lifetime
4256  volatile long _M_refcount;
4257 
4258  // The internal lock for this block for its message
4260 
4261  // connected targets
4262  _Target_registry _M_connectedTargets;
4263  };
4264 
4265  // static class that exposes methods to initiate messages into
4266  // a dataflow network
4268  {
4269  public:
4270 
4271  // Synchronous initiation of messages
4272  template <class _Type>
4273  static bool _send(ITarget<_Type> * _Trg, const _Type& _Data)
4274  {
4275  if (_Trg != NULL && _Trg->supports_anonymous_source())
4276  {
4277  // _send will block until the message is accepted/rejected.
4278  // Note that this invokes the send method on the target which
4279  // would synchronously process the message.
4280  _AnonymousOriginator<_Type> _Send_block;
4281  return _Send_block._internal_send(_Trg, _Data);
4282  }
4283  else
4284  {
4285  // Create a blocking originator on the stack. _send will block until the
4286  // message is accepted/rejected.
4287  _SyncOriginator<_Type> _Orig;
4288  return _Orig._internal_send(_Trg, _Data);
4289  }
4290  }
4291 
4292  // Asynchronous initiation of messages
4293  template <class _Type>
4294  static bool _asend(ITarget<_Type> * _Trg, const _Type& _Data)
4295  {
4296  // If the block can participate in posting messages without requiring a call back, use that
4297  // method of initiating the message rather for efficiency purposes.
4298  if (_Trg != NULL && _Trg->supports_anonymous_source())
4299  {
4300  _AnonymousOriginator<_Type> _Asend_block;
4301  return _Asend_block._internal_asend(_Trg, _Data);
4302  }
4303  else
4304  {
4305  // Needs to be allocated on the heap
4307  return _AsyncOrig->_internal_send(_Trg, _Data);
4308  }
4309  }
4310  };
4311 
4312 } // namespace details
4313 
4335 
4336 template <class _Type>
4337 bool send(_Inout_ ITarget<_Type> * _Trg, const _Type& _Data)
4338 {
4339  return details::_Originator::_send(_Trg, _Data);
4340 }
4341 
4342 
4364 
4365 template <class _Type>
4366 bool send(ITarget<_Type> &_Trg, const _Type &_Data)
4367 {
4368  return ::Concurrency::send(&_Trg, _Data);
4369 }
4370 
4392 
4393 template <class _Type>
4394 bool asend(_Inout_ ITarget<_Type> * _Trg, const _Type& _Data)
4395 {
4396  return details::_Originator::_asend(_Trg, _Data);
4397 }
4398 
4399 
4421 
4422 template <class _Type>
4423 bool asend(ITarget<_Type> &_Trg, const _Type &_Data)
4424 {
4425  return ::Concurrency::asend(&_Trg, _Data);
4426 }
4427 
4428 //**************************************************************************
4429 // Target Block:
4430 //**************************************************************************
4431 
4443 
4444 template<class _SourceLinkRegistry,
4445  class _MessageProcessorType = ordered_message_processor<typename _SourceLinkRegistry::type::source_type>>
4446 class target_block : public ITarget<typename _SourceLinkRegistry::type::source_type>
4447 {
4448 public:
4452 
4453  typedef typename _SourceLinkRegistry::type::source_type _Source_type;
4454 
4458 
4460 
4464 
4466 
4467  using typename ITarget<_Source_type>::filter_method;
4468 
4472 
4474  {
4478  }
4479 
4483 
4484  virtual ~target_block()
4485  {
4486  // All sources should have been unlinked
4488  delete _M_pFilter;
4489 
4491  }
4492 
4510 
4512  {
4513  // It is important that calls to propagate do *not* take the same lock on the
4514  // internal structure that is used by <c>consume</c> and the LWT. Doing so could
4515  // result in a deadlock.
4516 
4517  if (_PMessage == NULL)
4518  {
4519  throw std::invalid_argument("_PMessage");
4520  }
4521 
4522  if (_PSource == NULL)
4523  {
4524  throw std::invalid_argument("_PSource");
4525  }
4526 
4527  if (_M_fDeclineMessages)
4528  {
4529  return declined;
4530  }
4531 
4532  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
4533  {
4534  return declined;
4535  }
4536 
4537  return propagate_message(_PMessage, _PSource);
4538  }
4539 
4561 
4563  {
4564  if (_PMessage == NULL)
4565  {
4566  throw std::invalid_argument("_PMessage");
4567  }
4568 
4569  if (_PSource == NULL)
4570  {
4571  throw std::invalid_argument("_PSource");
4572  }
4573 
4574  if (_M_fDeclineMessages)
4575  {
4576  return declined;
4577  }
4578 
4579  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
4580  {
4581  return declined;
4582  }
4583 
4584  return send_message(_PMessage, _PSource);
4585  }
4586 
4587 protected:
4588 
4603 
4605 
4623 
4625  {
4626  // By default we do not allow send()
4627  return declined;
4628  }
4629 
4641 
4642  virtual void link_source(_Inout_ ISource<_Source_type> * _PSource)
4643  {
4644  _M_connectedSources.add(_PSource);
4648  }
4649 
4659 
4661  {
4665 
4666  _M_connectedSources.remove(_PSource);
4667  }
4668 
4672 
4673  virtual void unlink_sources()
4674  {
4675  for (source_iterator _Iter = _M_connectedSources.begin(); *_Iter != NULL; ++_Iter)
4676  {
4677  ISource<_Source_type> * _PSource = *_Iter;
4678  _PSource->unlink_target(this);
4679  }
4680  }
4681 
4688 
4690  {
4691  }
4692 
4693  //
4694  // Utility routines
4695  //
4696 
4704 
4705  void register_filter(filter_method const& _Filter)
4706  {
4707  if (_Filter != NULL)
4708  {
4709  _M_pFilter = new filter_method(_Filter);
4710  }
4711  }
4712 
4719 
4721  {
4722  _M_fDeclineMessages = true;
4723  }
4724 
4737 
4738  void initialize_target(_Inout_opt_ Scheduler * _PScheduler = NULL, _Inout_opt_ ScheduleGroup * _PScheduleGroup = NULL)
4739  {
4740  // Register a callback with the processor
4741  _M_messageProcessor.initialize(_PScheduler, _PScheduleGroup,
4742  // Processing and Propagating function used by ordered_message_processors
4743  [this](message<_Source_type> * _PMessage)
4744  {
4745  // Handle message by calling process_message to maintain CRT100 compatibility
4746  this->process_message(_PMessage);
4747  });
4748 
4749  // Register this target block as the owner of the connected sources
4751  }
4752 
4756 
4758  {
4759  _M_messageProcessor.initialize_batched_processing(
4760  // Processing function used by CRT110
4761  [this](message<_Source_type> * _PMessage)
4762  {
4763  // Handle message through new process_input_message to use CRT110 batch processing
4764  this->process_input_messages(_PMessage);
4765  }, nullptr);
4766  }
4767 
4774 
4776  {
4777  _M_messageProcessor.async_send(_PMessage);
4778  }
4779 
4786 
4788  {
4789  _M_messageProcessor.sync_send(_PMessage);
4790  }
4791 
4799 
4801  {
4802  // Decline new messages to ensure that messages are not dropped during the wait
4804 
4805  _M_messageProcessor.wait();
4806  }
4807 
4814 
4816  {
4818 
4819  unlink_sources();
4820  }
4821 
4825 
4827  {
4828  throw invalid_operation("To use batched processing, you must override process_input_messages in the message block.");
4829  }
4830 
4834 
4835  _SourceLinkManager _M_connectedSources;
4836 
4840 
4842 
4847 
4849 
4853 
4854  _MessageProcessorType _M_messageProcessor;
4855 };
4856 
4857 //**************************************************************************
4858 // Source Block:
4859 //**************************************************************************
4860 
4876 
4877 template<class _TargetLinkRegistry,
4879 class source_block : public ISource<typename _TargetLinkRegistry::type::type>
4880 {
4881 public:
4882 
4886 
4887  typedef typename _TargetLinkRegistry::type::type _Target_type;
4888 
4892 
4893  typedef typename _TargetLinkRegistry::iterator target_iterator;
4894 
4898 
4901  _M_reservedId(-1),
4903  {
4907  }
4908 
4912 
4913  virtual ~source_block()
4914  {
4915  // All targets should have been unlinked
4916  _CONCRT_ASSERT(_M_connectedTargets.count() == 0);
4917 
4919  }
4920 
4931 
4932  virtual void link_target(_Inout_ ITarget<_Target_type> * _PTarget)
4933  {
4934  _R_lock _Lock(_M_internalLock);
4935 
4936  if (_PTarget == NULL)
4937  {
4938  throw std::invalid_argument("_PTarget");
4939  }
4940 
4941  _M_connectedTargets.add(_PTarget);
4942  this->_Invoke_link_source(_PTarget);
4943  link_target_notification(_PTarget);
4944  }
4945 
4956 
4958  {
4959  _R_lock _Lock(_M_internalLock);
4960 
4961  if (_PTarget == NULL)
4962  {
4963  throw std::invalid_argument("_PTarget");
4964  }
4965 
4966  if (_M_connectedTargets.remove(_PTarget))
4967  {
4968  // We were able to remove the target from our list.
4969  // Inform the target to unlink from us
4970  this->_Invoke_unlink_source(_PTarget);
4971  }
4972  }
4973 
4977 
4978  virtual void unlink_targets()
4979  {
4980  _R_lock _Lock(_M_internalLock);
4981 
4982  for (target_iterator _Iter = _M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
4983  {
4984  ITarget<_Target_type> * _PTarget = *_Iter;
4985  _CONCRT_ASSERT(_PTarget != NULL);
4986 
4987  unlink_target(_PTarget);
4988  }
4989 
4990  // All the targets should be unlinked.
4991  _CONCRT_ASSERT(_M_connectedTargets.count() == 0);
4992  }
4993 
5015 
5016  virtual message<_Target_type> * accept(runtime_object_identity _MsgId, _Inout_ ITarget<_Target_type> * _PTarget)
5017  {
5018  if (_PTarget == NULL)
5019  {
5020  throw std::invalid_argument("_PTarget");
5021  }
5022 
5023  // Assert if the target is not connected
5024  _CONCRT_ASSERT(_M_connectedTargets.contains(_PTarget));
5025 
5026  return accept_message(_MsgId);
5027  }
5028 
5051 
5052  virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget<_Target_type> * _PTarget)
5053  {
5054  _R_lock _Lock(_M_internalLock);
5055 
5056  if (_PTarget == NULL)
5057  {
5058  throw std::invalid_argument("_PTarget");
5059  }
5060 
5061  if ( _M_pReservedFor != NULL)
5062  {
5063  // Someone else is holding the reservation
5064  return false;
5065  }
5066 
5067  if (!reserve_message(_MsgId))
5068  {
5069  // Failed to reserve the msg ID
5070  return false;
5071  }
5072 
5073  // Save the reserving target and the msg ID
5074  _M_pReservedFor = _PTarget;
5075  _M_reservedId = _MsgId;
5076 
5077  return true;
5078  }
5079 
5107 
5108  virtual message<_Target_type> * consume(runtime_object_identity _MsgId, _Inout_ ITarget<_Target_type> * _PTarget)
5109  {
5110  _R_lock _Lock(_M_internalLock);
5111 
5112  if (_PTarget == NULL)
5113  {
5114  throw std::invalid_argument("_PTarget");
5115  }
5116 
5117  if (_M_pReservedFor == NULL || _PTarget != _M_pReservedFor)
5118  {
5119  throw bad_target();
5120  }
5121 
5122  message<_Target_type> * _Msg = consume_message(_MsgId);
5123 
5124  if (_Msg != NULL)
5125  {
5126  // Clear the reservation
5127  // _M_pReservedId is intentionally not reset so that it can assist in debugging
5129 
5130  // Reservation is assumed to block propagation. Notify that propagation can now be resumed
5132  }
5133 
5134  return _Msg;
5135  }
5136 
5156 
5157  virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget<_Target_type> * _PTarget)
5158  {
5159  _R_lock _Lock(_M_internalLock);
5160 
5161  if (_PTarget == NULL)
5162  {
5163  throw std::invalid_argument("_PTarget");
5164  }
5165 
5166  if (_PTarget != _M_pReservedFor)
5167  {
5168  throw bad_target();
5169  }
5170 
5171  release_message(_MsgId);
5172 
5173  // Clear the reservation
5174  // _M_pReservedId is intentionally not reset so that it can assist in debugging
5176 
5177  // Reservation is assumed to block propagation. Notify that propagation can now be resumed
5179  }
5180 
5191 
5193  {
5195  }
5196 
5207 
5208  virtual void release_ref(_Inout_ ITarget<_Target_type> * _PTarget)
5209  {
5210  if (_PTarget != NULL)
5211  {
5212  _R_lock _Lock(_M_internalLock);
5213 
5214  // We assume that each target would keep a single reference on its source, so
5215  // we call unlink target notification on every release. Otherwise, we would be
5216  // required to keep a reference count per target.
5217  // Note: unlink_target_notification can check the value of this _PTarget pointer, but
5218  // must not dereference it, as it may have already been deleted.
5219  unlink_target_notification(_PTarget);
5220  }
5221 
5223 
5224  // It is *unsafe* to touch the "this" pointer after decrementing the reference count
5225  }
5226 
5227 protected:
5228 
5229  //
5230  // Protected methods that a derived class can override to customize
5231  // the functionality
5232  //
5233 
5240 
5242  {
5243  // By default, we restart propagation if there is no pending reservation
5244  if (_M_pReservedFor == NULL)
5245  {
5247  }
5248  }
5249 
5256 
5258  {
5259  // At this point, the target has already been disconnected from the
5260  // source. It is safe to check the value of this pointer, but not
5261  // safe to dereference it, as it may have already been deleted.
5262 
5263  // If the target being unlinked is the one holding the reservation,
5264  // release the reservation
5265  if (_M_pReservedFor == _PTarget)
5266  {
5267  release(_M_reservedId, _PTarget);
5268  }
5269  }
5270 
5286 
5287  virtual message<_Target_type> * accept_message(runtime_object_identity _MsgId) = 0;
5288 
5303 
5304  virtual bool reserve_message(runtime_object_identity _MsgId) = 0;
5305 
5318 
5319  virtual message<_Target_type> * consume_message(runtime_object_identity _MsgId) = 0;
5320 
5327 
5328  virtual void release_message(runtime_object_identity _MsgId) = 0;
5329 
5333 
5334  virtual void resume_propagation() = 0;
5335 
5339 
5341  {
5342  // source_blocks do not need to process anything
5343  }
5344 
5348 
5350  {
5351  throw invalid_operation("To use batched processing, you must override propagate_output_messages in the message block.");
5352  }
5353 
5361 
5363  {
5364  throw invalid_operation("To use ordered message processing, you must override propagate_to_any_targets in the message block.");
5365  }
5366 
5367  //
5368  // Utility routines
5369  //
5381 
5382  void initialize_source(_Inout_opt_ Scheduler * _PScheduler = NULL, _Inout_opt_ ScheduleGroup * _PScheduleGroup = NULL)
5383  {
5384  // Register a callback
5385  _M_messageProcessor.initialize(_PScheduler, _PScheduleGroup,
5386  [this](message<_Target_type> * _PMessage)
5387  {
5388  this->_Handle_message(_PMessage);
5389  });
5390  }
5391 
5395 
5397  {
5398  // Register callbacks for CRT110 batched processing
5399  _M_messageProcessor.initialize_batched_processing(
5400  // Processing function used by CRT110
5401  [this](message<_Target_type> * _PMessage)
5402  {
5403  // Handle message through new process_input_message to use CRT110 batch processing
5404  this->process_input_messages(_PMessage);
5405  },
5406  [this](void)
5407  {
5408  this->_Propagate_message();
5409  });
5410  }
5411 
5419 
5421  {
5422  // Caller shall not be holding any locks when calling this routine
5423  _M_messageProcessor.sync_send(_Msg);
5424  }
5425 
5433 
5435  {
5436  _M_messageProcessor.async_send(_Msg);
5437  }
5438 
5444 
5446  {
5447  _M_messageProcessor.wait();
5448  }
5449 
5453 
5455  {
5456  // Wait for outstanding propagation to complete.
5458 
5459  unlink_targets();
5460 
5461  _Wait_on_ref();
5462  }
5463 
5464  //
5465  // Protected members
5466  //
5467 
5471 
5473 
5477 
5478  runtime_object_identity _M_reservedId;
5479 
5483 
5484  _TargetLinkRegistry _M_connectedTargets;
5485 
5489 
5490  _MessageProcessorType _M_messageProcessor;
5491 
5492 private:
5493 
5495 
5496 
5497  // Message handler callback for the propagator. Invokes propagate_to_any_targets
5498  // which derived classes should implement.
5499 
5501  {
5502  // Hold a lock to synchronize with unlink targets
5503  _R_lock _Lock(_M_internalLock);
5504  propagate_to_any_targets(_PMessage);
5505  }
5506 
5507  // Message handler callback for the processor. Invokes process_input_messages
5508  // which derived classes should implement.
5509 
5511  {
5512  // Don't need a lock to process the message
5513  process_input_messages(_PMessage);
5514  }
5515 
5516  // Message handler callback for the propagator. Invokes propagate_output_messages
5517  // which derived classes should implement.
5518 
5520  {
5521  // Hold a lock to synchronize with unlink targets
5522  _R_lock _Lock(_M_internalLock);
5524  }
5525 
5526  // Wait for the reference on this block to drop to zero
5527 
5528  void _Wait_on_ref(long _RefCount = 0)
5529  {
5531  while(_M_referenceCount != _RefCount)
5532  {
5533  spinWait._SpinOnce();
5534  }
5535  }
5536 
5537  // Private Data members
5538 
5545 
5547 
5548  volatile long _M_referenceCount;
5549 
5550 };
5551 
5552 //**************************************************************************
5553 // Propagator (source and target) Block:
5554 //**************************************************************************
5574 
5575 template<class _TargetLinkRegistry, class _SourceLinkRegistry,
5577 class propagator_block : public source_block<_TargetLinkRegistry, _MessageProcessorType>, public ITarget<typename _SourceLinkRegistry::type::source_type>
5578 {
5579 public:
5583 
5584  typedef typename _SourceLinkRegistry::type::source_type _Source_type;
5585 
5589 
5591 
5595 
5597 
5599  using typename ITarget<_Source_type>::filter_method;
5600 
5604 
5606  {
5607  }
5608 
5612 
5614  {
5616 
5617  delete _M_pFilter;
5618  }
5619 
5639 
5641  {
5642  // It is important that calls to propagate do *not* take the same lock on the
5643  // internal structure that is used by <c>consume</c> and the LWT. Doing so could
5644  // result in a deadlock.
5645 
5646  if (_PMessage == NULL)
5647  {
5648  throw std::invalid_argument("_PMessage");
5649  }
5650 
5651  if (_PSource == NULL)
5652  {
5653  throw std::invalid_argument("_PSource");
5654  }
5655 
5656  if (_M_fDeclineMessages)
5657  {
5658  return declined;
5659  }
5660 
5661  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
5662  {
5663  return declined;
5664  }
5665 
5666  return propagate_message(_PMessage, _PSource);
5667  }
5668 
5687 
5689  {
5690  if (_PMessage == NULL)
5691  {
5692  throw std::invalid_argument("_PMessage");
5693  }
5694 
5695  if (_PSource == NULL)
5696  {
5697  throw std::invalid_argument("_PSource");
5698  }
5699 
5700  if (_M_fDeclineMessages)
5701  {
5702  return declined;
5703  }
5704 
5705  if (_M_pFilter != NULL && !(*_M_pFilter)(_PMessage->payload))
5706  {
5707  return declined;
5708  }
5709 
5710  return send_message(_PMessage, _PSource);
5711  }
5712 
5713 protected:
5714 
5729 
5731 
5749 
5751  {
5752  // By default we do not allow send()
5753  return declined;
5754  }
5755 
5762 
5763  virtual void link_source(_Inout_ ISource<_Source_type> * _PSource)
5764  {
5765  _M_connectedSources.add(_PSource);
5769  }
5770 
5777 
5779  {
5783 
5784  _M_connectedSources.remove(_PSource);
5785  }
5786 
5790 
5791  virtual void unlink_sources()
5792  {
5793  for (source_iterator _Iter = _M_connectedSources.begin(); *_Iter != NULL; ++_Iter)
5794  {
5795  ISource<_Source_type> * _PSource = *_Iter;
5796  _PSource->unlink_target(this);
5797  }
5798  }
5799 
5800  //
5801  // Utility routines
5802  //
5803 
5807 
5809  {
5810  throw invalid_operation("To use batched processing, you must override process_input_messages in the message block.");
5811  }
5812 
5825 
5826  void initialize_source_and_target(_Inout_opt_ Scheduler * _PScheduler = NULL, _Inout_opt_ ScheduleGroup * _PScheduleGroup = NULL)
5827  {
5828  this->initialize_source(_PScheduler, _PScheduleGroup);
5829 
5830  // Register this propagator block as the owner of the connected sources
5832  }
5833 
5840 
5841  void register_filter(filter_method const& _Filter)
5842  {
5843  if (_Filter != NULL)
5844  {
5845  _M_pFilter = new filter_method(_Filter);
5846  }
5847  }
5848 
5855 
5857  {
5858  _M_fDeclineMessages = true;
5859  }
5860 
5864 
5866  {
5867  // Decline messages while the links are being removed
5869 
5870  // Remove all the target links. This waits for
5871  // all outstanding async propagation operations.
5872  this->remove_targets();
5873 
5874  // unlink all sources. The above steps guarantee that
5875  // they can be removed safely.
5876  unlink_sources();
5877  }
5878 
5882 
5883  _SourceLinkManager _M_connectedSources;
5884 
5888 
5890 
5895 
5896  volatile bool _M_fDeclineMessages;
5897 };
5898 
5899 //**************************************************************************
5900 // Unbounded Buffers:
5901 //**************************************************************************
5902 
5915 
5916 template<class _Type>
5917 class unbounded_buffer : public propagator_block<multi_link_registry<ITarget<_Type>>, multi_link_registry<ISource<_Type>>>
5918 {
5919 private:
5922 
5923 public:
5927 
5940 
5943  {
5945  this->enable_batched_processing();
5946  }
5947 
5963 
5966  {
5968  this->enable_batched_processing();
5969  this->register_filter(_Filter);
5970  }
5971 
5972 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
5973 
5989  unbounded_buffer(Scheduler& _PScheduler) :
5991  {
5992  this->initialize_source_and_target(&_PScheduler);
5993  this->enable_batched_processing();
5994  }
5995 
6014 
6015  unbounded_buffer(Scheduler& _PScheduler, filter_method const& _Filter) :
6017  {
6018  this->initialize_source_and_target(&_PScheduler);
6019  this->enable_batched_processing();
6020  this->register_filter(_Filter);
6021  }
6022 
6039 
6040  unbounded_buffer(ScheduleGroup& _PScheduleGroup) :
6042  {
6043  this->initialize_source_and_target(NULL, &_PScheduleGroup);
6044  this->enable_batched_processing();
6045  }
6046 
6066 
6067  unbounded_buffer(ScheduleGroup& _PScheduleGroup, filter_method const& _Filter) :
6069  {
6070  this->initialize_source_and_target(NULL, &_PScheduleGroup);
6071  this->enable_batched_processing();
6072  this->register_filter(_Filter);
6073  }
6074 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
6075 
6079 
6081  {
6082  // Remove all links
6083  this->remove_network_links();
6084 
6085  // Clean up any messages left in this message block
6087  }
6088 
6098 
6099  bool enqueue(_Type const& _Item)
6100  {
6101  return ::Concurrency::send<_Type>(this, _Item);
6102  }
6103 
6110 
6111  _Type dequeue()
6112  {
6113  return ::Concurrency::receive<_Type>(this);
6114  }
6115 
6116 
6117 protected:
6118 
6119  //
6120  // propagator_block protected function implementations
6121  //
6122 
6137 
6139  {
6140  // It is important that calls to propagate do *not* take the same lock on the
6141  // internal structure that is used by <c>consume</c> and the LWT. Doing so could
6142  // result in a deadlock.
6143 
6144  message_status _Result = accepted;
6145 
6146  // Accept the message being propagated
6147  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
6148 
6149  if (_PMessage != NULL)
6150  {
6151  this->async_send(_PMessage);
6152  }
6153  else
6154  {
6155  _Result = missed;
6156  }
6157 
6158  return _Result;
6159  }
6160 
6175 
6177  {
6178  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
6179 
6180  if (_PMessage != NULL)
6181  {
6182  this->sync_send(_PMessage);
6183  }
6184  else
6185  {
6186  return missed;
6187  }
6188 
6189  return accepted;
6190  }
6191 
6199 
6201  {
6202  return true;
6203  }
6204 
6215 
6216  virtual message<_Type> * accept_message(runtime_object_identity _MsgId)
6217  {
6218  //
6219  // Peek at the head message in the message buffer. If the IDs match
6220  // dequeue and transfer ownership
6221  //
6222  message<_Type> * _Msg = NULL;
6223 
6224  if (_M_messageBuffer._Is_head(_MsgId))
6225  {
6226  _Msg = _M_messageBuffer._Dequeue();
6227  }
6228 
6229  return _Msg;
6230  }
6231 
6245 
6246  virtual bool reserve_message(runtime_object_identity _MsgId)
6247  {
6248  // Allow reservation if this is the head message
6249  return _M_messageBuffer._Is_head(_MsgId);
6250  }
6251 
6265 
6266  virtual message<_Type> * consume_message(runtime_object_identity _MsgId)
6267  {
6268  // By default, accept the message
6269  return accept_message(_MsgId);
6270  }
6271 
6278 
6279  virtual void release_message(runtime_object_identity _MsgId)
6280  {
6281  // The head message is the one reserved.
6282  if (!_M_messageBuffer._Is_head(_MsgId))
6283  {
6284  throw message_not_found();
6285  }
6286  }
6287 
6291 
6292  virtual void resume_propagation()
6293  {
6294  // If there are any messages in the buffer, propagate them out
6295  if (_M_messageBuffer._Count() > 0)
6296  {
6297  // Set the flag to force a repropagation. This flag is cleared when a propagation happens
6298  // The only functions that call this are release, consume, and link_target, all of which
6299  // hold the internal lock, so the flag is guaranteed to be read by propagation, which also
6300  // holds the same lock.
6301  _M_fForceRepropagation = true;
6302 
6303  // async send a NULL value to initiate the repropagation
6304  this->async_send(NULL);
6305  }
6306  }
6307 
6314 
6316  {
6317  // If the message queue is blocked due to reservation
6318  // there is no need to do any message propagation
6319  if (this->_M_pReservedFor != NULL)
6320  {
6321  return;
6322  }
6323 
6324  message<_Type> * _Msg = _M_messageBuffer._Peek();
6325 
6326  if (_Msg != NULL)
6327  {
6328  // Propagate the head message to the new target
6329  message_status _Status = _PTarget->propagate(_Msg, this);
6330 
6331  if (_Status == accepted)
6332  {
6333  // The target accepted the message, restart propagation.
6335  }
6336 
6337  // If the status is anything other than accepted, then leave
6338  // the message queue blocked.
6339  }
6340  }
6341 
6347  {
6348  if (_PMessage != NULL)
6349  {
6350  _M_processedMessages._Enqueue(_PMessage);
6351  }
6352  }
6353 
6367 
6369  {
6370  // Move the messages from the processedMessages queue to the internal storage
6371  // to make them ready for propagating out
6372 
6373  // If there are messages in the message queue, the queue is blocked and a
6374  // propagation should not happen unless it has been forced using resume_propagation
6375  bool _FIsBlocked = (_M_messageBuffer._Count() > 0);
6376 
6377  for(;;)
6378  {
6379  message<_Type> * _PInputMessage = _M_processedMessages._Dequeue();
6380  if(_PInputMessage == NULL)
6381  {
6382  break;
6383  }
6384  _M_messageBuffer._Enqueue(_PInputMessage);
6385  }
6386 
6387  if (_M_fForceRepropagation == false && _FIsBlocked == true)
6388  {
6389  return;
6390  }
6391 
6392  // Reset the repropagation flag because a propagation has started.
6393  _M_fForceRepropagation = false;
6394 
6395  // Attempt to propagate messages to all the targets
6397  }
6398 
6399 private:
6400 
6407 
6409  {
6410  message<_Target_type> * _Msg = _MessageBuffer._Peek();
6411 
6412  // If someone has reserved the _Head message, don't propagate anymore
6413  if (this->_M_pReservedFor != NULL)
6414  {
6415  return;
6416  }
6417 
6418  while (_Msg != NULL)
6419  {
6420  message_status _Status = declined;
6421 
6422  // Always start from the first target that linked
6423  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
6424  {
6425  ITarget<_Target_type> * _PTarget = *_Iter;
6426  _Status = _PTarget->propagate(_Msg, this);
6427 
6428  // Ownership of message changed. Do not propagate this
6429  // message to any other target.
6430  if (_Status == accepted)
6431  {
6432  break;
6433  }
6434 
6435  // If the target just propagated to reserved this message, stop
6436  // propagating it to others
6437  if (this->_M_pReservedFor != NULL)
6438  {
6439  break;
6440  }
6441  }
6442 
6443  // If status is anything other than accepted, then the head message
6444  // was not propagated out. Thus, nothing after it in the queue can
6445  // be propagated out. Cease propagation.
6446  if (_Status != accepted)
6447  {
6448  break;
6449  }
6450 
6451  // Get the next message
6452  _Msg = _MessageBuffer._Peek();
6453  }
6454  }
6455 
6460 
6462  {
6463  // Input messages for this message block are in the base-class input buffer
6464  // All messages in that buffer are guaranteed to have moved to the output
6465  // buffer because the destructor first waits for all async sends to finish
6466  // before reaching this point
6467 
6468  // Delete any messages remaining in the output queue
6469  for (;;)
6470  {
6471  message<_Type> * _Msg = _M_messageBuffer._Dequeue();
6472  if (_Msg == NULL)
6473  {
6474  break;
6475  }
6476  delete _Msg;
6477  }
6478  }
6479 
6483 
6485 
6489 
6491 
6495 
6497 
6498 private:
6499  //
6500  // Hide assignment operator and copy constructor
6501  //
6502  unbounded_buffer const &operator =(unbounded_buffer const&); // no assignment operator
6503  unbounded_buffer(unbounded_buffer const &); // no copy constructor
6504 };
6505 
6506 //**************************************************************************
6507 // Overwrite Buffers:
6508 //**************************************************************************
6509 
6524 
6525 template<class _Type>
6526 class overwrite_buffer : public propagator_block<multi_link_registry<ITarget<_Type>>, multi_link_registry<ISource<_Type>>>
6527 {
6528 private:
6531 
6532 public:
6535 
6548 
6551  {
6553  }
6554 
6570 
6573  {
6575  this->register_filter(_Filter);
6576  }
6577 
6578 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
6579 
6595  overwrite_buffer(Scheduler& _PScheduler) :
6597  {
6598  this->initialize_source_and_target(&_PScheduler);
6599  }
6600 
6619 
6620  overwrite_buffer(Scheduler& _PScheduler,
6621  filter_method const& _Filter) :
6623  {
6624  this->initialize_source_and_target(&_PScheduler);
6625  this->register_filter(_Filter);
6626  }
6627 
6644 
6645  overwrite_buffer(ScheduleGroup& _PScheduleGroup) :
6647  {
6648  this->initialize_source_and_target(NULL, &_PScheduleGroup);
6649  }
6650 
6670 
6671  overwrite_buffer(ScheduleGroup& _PScheduleGroup,
6672  filter_method const& _Filter) :
6674  {
6675  this->initialize_source_and_target(NULL, &_PScheduleGroup);
6676  this->register_filter(_Filter);
6677  }
6678 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
6679 
6683 
6685  {
6686  // Remove all links that are targets of this overwrite_buffer
6687  this->remove_network_links();
6688 
6689  // Clean up any messages left in this message block
6691  }
6692 
6699 
6700  bool has_value() const
6701  {
6702  return _M_fIsInitialized != 0;
6703  }
6704 
6715 
6716  _Type value()
6717  {
6718  return ::Concurrency::receive<_Type>(this);
6719  }
6720 
6721 protected:
6722 
6723  //
6724  // propagator_block protected function implementation
6725  //
6726 
6741 
6743  {
6744  // It is important that calls to propagate do *not* take the same lock on the
6745  // internal structure that is used by Consume and the LWT. Doing so could
6746  // result in a deadlock with the Consume call.
6747 
6748  message_status _Result = accepted;
6749 
6750  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
6751 
6752  //
6753  // If message was accepted, set the member variables for
6754  // this block and start the asynchronous propagation task
6755  //
6756  if (_PMessage != NULL)
6757  {
6758  // Add a reference for the async_send holding the message
6759  _PMessage->add_ref();
6760 
6761  this->async_send(_PMessage);
6762  }
6763  else
6764  {
6765  _Result = missed;
6766  }
6767 
6768  return _Result;
6769  }
6770 
6785 
6787  {
6788  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
6789 
6790  //
6791  // If message was accepted, set the member variables for
6792  // this block and start the asynchronous propagation task
6793  //
6794  if (_PMessage != NULL)
6795  {
6796  // Add a reference for the sync_send holding the message
6797  _PMessage->add_ref();
6798 
6799  this->sync_send(_PMessage);
6800  }
6801  else
6802  {
6803  return missed;
6804  }
6805 
6806  return accepted;
6807  }
6808 
6816 
6818  {
6819  return true;
6820  }
6821 
6837 
6838  virtual message<_Type> * accept_message(runtime_object_identity _MsgId)
6839  {
6840  //
6841  // If the internal message has not yet been initialized yet, return NULL
6842  //
6843  if (_M_pMessage == NULL)
6844  {
6845  return NULL;
6846  }
6847 
6848  //
6849  // Instead of returning the internal message, we return a copy of the
6850  // message stored.
6851  //
6852  // Because we are returning a copy, the accept routine for an overwritebuffer
6853  // does not need to grab the internalLock
6854  //
6855  message<_Type> * _Msg = NULL;
6856  if (_M_pMessage->msg_id() == _MsgId)
6857  {
6858  _Msg = new message<_Type>(_M_pMessage->payload);
6859  }
6860 
6861  return _Msg;
6862  }
6863 
6877 
6878  virtual bool reserve_message(runtime_object_identity _MsgId)
6879  {
6880  // Ensure that this message currently exists in the overwrite buffer
6881  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
6882  {
6883  return false;
6884  }
6885 
6886  // Can only reserve one message, any other blocks trying to reserve
6887  // will return false
6889 
6890  // Save this message away
6892 
6893  // Add a reference for this message to prevent deletion
6894  _M_pReservedMessage->add_ref();
6895 
6896  return true;
6897  }
6898 
6912 
6913  virtual message<_Type> * consume_message(runtime_object_identity _MsgId)
6914  {
6915  // Leave and return NULL if this msgId doesn't match the reserved message
6916  // Otherwise this is a pull of a later overwritten message, and messages
6917  // could them appear out of order.
6918  if (_M_pReservedMessage != NULL && _M_pReservedMessage->msg_id() != _MsgId)
6919  {
6920  return NULL;
6921  }
6922  // This redundant assert is specifically to make the /analyze switch happy, which cannot recognize the same assertion above in if stmnt.
6924 
6925  _Type _Payload = _M_pReservedMessage->payload;
6926 
6927  // Take the reserved message
6928  message<_Type> * _Result = new message<_Type>(_Payload);
6929 
6930  if (_M_pReservedMessage->remove_ref() == 0)
6931  {
6932  delete _M_pReservedMessage;
6933  }
6935 
6936  return _Result;
6937  }
6938 
6945 
6946  virtual void release_message(runtime_object_identity _MsgId)
6947  {
6950 
6951  if (_MsgId != _M_pReservedMessage->msg_id())
6952  {
6953  throw message_not_found();
6954  }
6955 
6956  if (_M_pReservedMessage->remove_ref() == 0)
6957  {
6958  delete _M_pReservedMessage;
6959  }
6961  }
6962 
6966 
6967  virtual void resume_propagation()
6968  {
6969  // On reservation we do not stop propagation. So there
6970  // is nothing to be done to resume propagation.
6971  }
6972 
6979 
6981  {
6982  // If there is a message available already, propagate it
6983  if (_M_pMessage != NULL)
6984  {
6985  _PTarget->propagate(_M_pMessage, this);
6986  }
6987  }
6988 
7000 
7002  {
7003  // Move the message from the queuedMessages Buffer to the internal storage
7004 
7005  // Add a reference for the overwrite_buffer holding the message
7006  _PMessage->add_ref();
7007 
7008  if (_M_pMessage != NULL)
7009  {
7010  if (_M_pMessage->remove_ref() == 0)
7011  {
7012  delete _M_pMessage;
7013  }
7014  }
7015 
7016  _M_pMessage = _PMessage;
7017 
7018  // Now that message has been received, set this block as initialized
7019  _M_fIsInitialized = true;
7020 
7021  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
7022  {
7023  // Overwrite buffers can propagate its message out
7024  // to any number of Targets
7025 
7026  ITarget<_Type> * _PTarget = *_Iter;
7027  _PTarget->propagate(_PMessage, this);
7028  }
7029 
7030  if (_PMessage->remove_ref() == 0)
7031  {
7032  delete _PMessage;
7033  }
7034  }
7035 
7036 private:
7037 
7042 
7044  {
7045  // Input messages for this message block are in the base-class input buffer
7046  // All messages in that buffer are guaranteed to have moved to the output
7047  // buffer because the destructor first waits for all async sends to finish
7048  // before reaching this point
7049 
7050  // The messages for an overwrite buffer are deleted when overwritten
7051  // through reference counting. This final check is put in place in
7052  // case any message still exists in the buffer when the overwrite_buffer
7053  // is deleted. The reference count of this message has not yet reached
7054  // zero because it hasn't been overwritten yet. It is safe because of
7055  // we have finished all propagation.
7056  if (_M_pMessage != NULL)
7057  {
7058  // A block can only have a reserved message after receiving a message
7059  // at some point, so it must be within the above if-clause.
7060  // Now delete the reserved message if it is non-NULL and different from
7061  // the saved internal message
7063  {
7064  delete _M_pReservedMessage;
7065  }
7066  delete _M_pMessage;
7067  }
7068  }
7069 
7070  //
7071  // Private Data Members
7072  //
7073 
7074  // The message being stored
7076 
7077  // The message being reserved
7079 
7080  // The marker for whether the overwrite buffer has already been initialized
7081  volatile bool _M_fIsInitialized;
7082 
7083 private:
7084  //
7085  // Hide assignment operator and copy constructor
7086  //
7087  overwrite_buffer const &operator =(overwrite_buffer const&); // no assignment operator
7088  overwrite_buffer(overwrite_buffer const &); // no copy constructor
7089 };
7090 
7091 //**************************************************************************
7092 // Call:
7093 //**************************************************************************
7094 
7109 
7110 template<class _Type, class _FunctorType = std::function<void(_Type const&)>>
7111 class call : public target_block<multi_link_registry<ISource<_Type>>>
7112 {
7113 private:
7117 
7118  typedef _FunctorType _Call_method;
7119 
7121 
7122 public:
7124 
7142 
7143  call(_Call_method const& _Func) :
7144  _M_pFunc(_Func)
7145  {
7146  this->initialize_target();
7147  this->enable_batched_processing();
7148  }
7149 
7167 
7168  call(_Call_method const& _Func,
7169  filter_method const& _Filter) :
7170  _M_pFunc(_Func)
7171  {
7172  this->initialize_target();
7173  this->enable_batched_processing();
7174  this->register_filter(_Filter);
7175  }
7176 
7177 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
7178 
7199  call(Scheduler& _PScheduler,
7200  _Call_method const& _Func) :
7201  _M_pFunc(_Func)
7202  {
7203  this->initialize_target(&_PScheduler);
7204  this->enable_batched_processing();
7205  }
7206 
7230 
7231  call(Scheduler& _PScheduler,
7232  _Call_method const& _Func,
7233  filter_method const& _Filter) :
7234  _M_pFunc(_Func)
7235  {
7236  this->initialize_target(&_PScheduler);
7237  this->enable_batched_processing();
7238  this->register_filter(_Filter);
7239  }
7240 
7262 
7263  call(ScheduleGroup& _PScheduleGroup,
7264  _Call_method const& _Func) :
7265  _M_pFunc(_Func)
7266  {
7267  this->initialize_target(NULL, &_PScheduleGroup);
7268  this->enable_batched_processing();
7269  }
7270 
7295 
7296  call(ScheduleGroup& _PScheduleGroup,
7297  _Call_method const& _Func,
7298  filter_method const& _Filter) :
7299  _M_pFunc(_Func)
7300  {
7301  this->initialize_target(NULL, &_PScheduleGroup);
7302  this->enable_batched_processing();
7303  this->register_filter(_Filter);
7304  }
7305 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
7306 
7310 
7312  {
7313  this->remove_sources();
7314  }
7315 
7316 protected:
7317 
7318  //
7319  // target_block protected function implementations
7320  //
7321 
7336 
7338  {
7339  // It is important that calls to propagate do *not* take the same lock on the
7340  // internal structure that is used by Consume and the LWT. Doing so could
7341  // result in a deadlock with the Consume call.
7342 
7343  message_status _Result = accepted;
7344 
7345  //
7346  // Accept the message being propagated
7347  // Note: depending on the source block propagating the message
7348  // this may not necessarily be the same message (pMessage) first
7349  // passed into the function.
7350  //
7351  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
7352 
7353  if (_PMessage != NULL)
7354  {
7355  this->async_send(_PMessage);
7356  }
7357  else
7358  {
7359  _Result = missed;
7360  }
7361 
7362  return _Result;
7363  }
7364 
7379 
7381  {
7382  message_status _Result = accepted;
7383 
7384  //
7385  // Accept the message being propagated
7386  // Note: depending on the source block propagating the message
7387  // this may not necessarily be the same message (pMessage) first
7388  // passed into the function.
7389  //
7390  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
7391 
7392  if (_PMessage != NULL)
7393  {
7394  this->sync_send(_PMessage);
7395  }
7396  else
7397  {
7398  _Result = missed;
7399  }
7400 
7401  return _Result;
7402  }
7403 
7411 
7413  {
7414  return true;
7415  }
7416 
7423 
7424  virtual void process_message(_Inout_ message<_Type> * _PMessage)
7425  {
7426  // No longer necessary with CRT110 change
7427  }
7428 
7432 
7434  {
7435  // Invoke the function provided by the user
7436  _CONCRT_ASSERT(_PMessage != NULL);
7437  _M_pFunc(_PMessage->payload);
7438  delete _PMessage;
7439  }
7440 
7441 private:
7442 
7443  //
7444  // Private Data Members
7445  //
7446 
7447  // The call method called by this block
7448  _Call_method _M_pFunc;
7449 
7450 private:
7451  //
7452  // Hide assignment operator and copy constructor
7453  //
7454  call const &operator =(call const&); // no assignment operator
7455  call(call const &); // no copy constructor
7456 };
7457 
7458 //**************************************************************************
7459 // Transformer:
7460 //**************************************************************************
7461 
7477 
7478 template<class _Input, class _Output>
7479 class transformer : public propagator_block<single_link_registry<ITarget<_Output>>, multi_link_registry<ISource<_Input>>>
7480 {
7481 private:
7482  typedef std::function<_Output(_Input const&)> _Transform_method;
7485 
7486 public:
7490 
7511 
7512  transformer(_Transform_method const& _Func,
7513  _Inout_opt_ ITarget<_Output> * _PTarget = NULL) :
7514  _M_pFunc(_Func)
7515  {
7517 
7518  if (_PTarget != NULL)
7519  {
7520  this->link_target(_PTarget);
7521  }
7522  }
7523 
7547 
7548  transformer(_Transform_method const& _Func,
7549  _Inout_opt_ ITarget<_Output> * _PTarget,
7550  filter_method const& _Filter) :
7551  _M_pFunc(_Func)
7552  {
7554  this->register_filter(_Filter);
7555 
7556  if (_PTarget != NULL)
7557  {
7558  this->link_target(_PTarget);
7559  }
7560  }
7561 
7562 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
7563 
7587  transformer(Scheduler& _PScheduler,
7588  _Transform_method const& _Func,
7589  _Inout_opt_ ITarget<_Output> * _PTarget = NULL) :
7590  _M_pFunc(_Func)
7591  {
7592  this->initialize_source_and_target(&_PScheduler);
7593 
7594  if (_PTarget != NULL)
7595  {
7596  this->link_target(_PTarget);
7597  }
7598  }
7599 
7626 
7627  transformer(Scheduler& _PScheduler,
7628  _Transform_method const& _Func,
7629  _Inout_opt_ ITarget<_Output> * _PTarget,
7630  filter_method const& _Filter) :
7631  _M_pFunc(_Func)
7632  {
7633  this->initialize_source_and_target(&_PScheduler);
7634  this->register_filter(_Filter);
7635 
7636  if (_PTarget != NULL)
7637  {
7638  this->link_target(_PTarget);
7639  }
7640  }
7641 
7666 
7667  transformer(ScheduleGroup& _PScheduleGroup,
7668  _Transform_method const& _Func,
7669  _Inout_opt_ ITarget<_Output> * _PTarget = NULL) :
7670  _M_pFunc(_Func)
7671  {
7672  this->initialize_source_and_target(NULL, &_PScheduleGroup);
7673 
7674  if (_PTarget != NULL)
7675  {
7676  this->link_target(_PTarget);
7677  }
7678  }
7679 
7707 
7708  transformer(ScheduleGroup& _PScheduleGroup,
7709  _Transform_method const& _Func,
7710  _Inout_opt_ ITarget<_Output> * _PTarget,
7711  filter_method const& _Filter) :
7712  _M_pFunc(_Func)
7713  {
7714  this->initialize_source_and_target(NULL, &_PScheduleGroup);
7715  this->register_filter(_Filter);
7716 
7717  if (_PTarget != NULL)
7718  {
7719  this->link_target(_PTarget);
7720  }
7721  }
7722 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
7723 
7727 
7729  {
7730  // Remove all links
7731  this->remove_network_links();
7732 
7733  // Clean up any messages left in this message block
7735  }
7736 
7737 protected:
7738 
7739  // Propagator_block protected function implementations
7740 
7755 
7757  {
7758  // It is important that calls to propagate do *not* take the same lock on the
7759  // internal structure that is used by Consume and the LWT. Doing so could
7760  // result in a deadlock with the Consume call.
7761 
7762  message_status _Result = accepted;
7763 
7764  //
7765  // Accept the message being propagated
7766  // Note: depending on the source block propagating the message
7767  // this may not necessarily be the same message (pMessage) first
7768  // passed into the function.
7769  //
7770  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
7771 
7772  if (_PMessage != NULL)
7773  {
7774  // Enqueue the input message
7775  _M_inputMessages.push(_PMessage);
7776  this->async_send(NULL);
7777  }
7778  else
7779  {
7780  _Result = missed;
7781  }
7782 
7783  return _Result;
7784  }
7785 
7800 
7802  {
7803  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
7804 
7805  if (_PMessage != NULL)
7806  {
7807  // Enqueue the input message
7808  _M_inputMessages.push(_PMessage);
7809  this->sync_send(NULL);
7810  }
7811  else
7812  {
7813  return missed;
7814  }
7815 
7816  return accepted;
7817  }
7818 
7826 
7828  {
7829  return true;
7830  }
7831 
7842 
7843  virtual message<_Output> * accept_message(runtime_object_identity _MsgId)
7844  {
7845  //
7846  // Peek at the head message in the message buffer. If the IDs match
7847  // dequeue and transfer ownership
7848  //
7849  message<_Output> * _Msg = NULL;
7850 
7851  if (_M_messageBuffer._Is_head(_MsgId))
7852  {
7853  _Msg = _M_messageBuffer._Dequeue();
7854  }
7855 
7856  return _Msg;
7857  }
7858 
7872 
7873  virtual bool reserve_message(runtime_object_identity _MsgId)
7874  {
7875  // Allow reservation if this is the head message
7876  return _M_messageBuffer._Is_head(_MsgId);
7877  }
7878 
7892 
7893  virtual message<_Output> * consume_message(runtime_object_identity _MsgId)
7894  {
7895  // By default, accept the message
7896  return accept_message(_MsgId);
7897  }
7898 
7905 
7906  virtual void release_message(runtime_object_identity _MsgId)
7907  {
7908  // The head message is the one reserved.
7909  if (!_M_messageBuffer._Is_head(_MsgId))
7910  {
7911  throw message_not_found();
7912  }
7913  }
7914 
7918 
7919  virtual void resume_propagation()
7920  {
7921  // If there are any messages in the buffer, propagate them out
7922  if (_M_messageBuffer._Count() > 0)
7923  {
7924  // async send a NULL value to initiate the repropagation
7925  this->async_send(NULL);
7926  }
7927  }
7928 
7935 
7937  {
7938  // If the message queue is blocked due to reservation
7939  // there is no need to do any message propagation
7940  if (this->_M_pReservedFor != NULL)
7941  {
7942  return;
7943  }
7944 
7946  }
7947 
7951 
7953  {
7954  message<_Output> * _Msg = NULL;
7955 
7956  // Process input message.
7957  message<_Input> * _PInputMessage = NULL;
7958  _M_inputMessages.try_pop(_PInputMessage);
7959 
7960  if (_PInputMessage != NULL)
7961  {
7962  // Invoke the TransformMethod on the data
7963  // Let exceptions flow
7964  _Output _Out = _M_pFunc(_PInputMessage->payload);
7965 
7966  // Reuse the input message ID
7967  _Msg = new message<_Output>(_Out, _PInputMessage->msg_id());
7968  _M_messageBuffer._Enqueue(_Msg);
7969 
7970  // Message cleanup
7971  delete _PInputMessage;
7972 
7973  if (!_M_messageBuffer._Is_head(_Msg->msg_id()))
7974  {
7975  return;
7976  }
7977  }
7978 
7980  }
7981 
7982 private:
7983 
7990 
7992  {
7993  message<_Target_type> * _Msg = _MessageBuffer._Peek();
7994 
7995  // If someone has reserved the _Head message, don't propagate anymore
7996  if (this->_M_pReservedFor != NULL)
7997  {
7998  return;
7999  }
8000 
8001  while (_Msg != NULL)
8002  {
8003  message_status _Status = declined;
8004 
8005  // Always start from the first target that linked
8006  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
8007  {
8008  ITarget<_Target_type> * _PTarget = *_Iter;
8009  _Status = _PTarget->propagate(_Msg, this);
8010 
8011  // Ownership of message changed. Do not propagate this
8012  // message to any other target.
8013  if (_Status == accepted)
8014  {
8015  break;
8016  }
8017 
8018  // If the target just propagated to reserved this message, stop
8019  // propagating it to others
8020  if (this->_M_pReservedFor != NULL)
8021  {
8022  break;
8023  }
8024  }
8025 
8026  // If status is anything other than accepted, then the head message
8027  // was not propagated out. Thus, nothing after it in the queue can
8028  // be propagated out. Cease propagation.
8029  if (_Status != accepted)
8030  {
8031  break;
8032  }
8033 
8034  // Get the next message
8035  _Msg = _MessageBuffer._Peek();
8036  }
8037  }
8038 
8043 
8045  {
8046  // Delete input messages
8047  // Because the transformer uses its own input queue, it's possible there are messages
8048  // in this queue and no LWT will be executed to handle them.
8049  message<_Input> * _PInputQueueMessage = NULL;
8050 
8051  while (_M_inputMessages.try_pop(_PInputQueueMessage))
8052  {
8053  // Message cleanup
8054  delete _PInputQueueMessage;
8055  }
8056 
8057  // Delete any messages remaining in the output queue
8058  for (;;)
8059  {
8060  message<_Output> * _Msg = _M_messageBuffer._Dequeue();
8061  if (_Msg == NULL)
8062  {
8063  break;
8064  }
8065  delete _Msg;
8066  }
8067  }
8068 
8069  //
8070  // Private Data Members
8071  //
8072 
8073  // The transformer method called by this block
8074  _Transform_method _M_pFunc;
8075 
8076  // The queue of input messages for this Transformer block
8078 
8082 
8084 
8085 private:
8086  //
8087  // Hide assignment operator and copy constructor
8088  //
8089  transformer const &operator =(transformer const &); // no assignment operator
8090  transformer(transformer const &); // no copy constructor
8091 };
8092 
8093 //**************************************************************************
8094 // Timer:
8095 //**************************************************************************
8107 
8108 template<class _Type>
8109 class timer : public ::Concurrency::details::_Timer, public source_block<single_link_registry<ITarget<_Type>>>
8110 {
8111 private:
8113 public:
8115 
8116 private:
8120 
8121  enum State
8122  {
8126 
8131 
8136 
8141 
8143  };
8144 
8145 public:
8146 
8169 
8170  timer(unsigned int _Ms, _Type const& _Value, ITarget<_Type> *_PTarget = NULL, bool _Repeating = false) :
8171  _Timer(_Ms, _Repeating)
8172  {
8173  _Initialize(_Value, _PTarget, _Repeating);
8174  }
8175 
8176 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
8177 
8203  timer(Scheduler& _Scheduler, unsigned int _Ms, _Type const& _Value, _Inout_opt_ ITarget<_Type> *_PTarget = NULL, bool _Repeating = false) :
8204  _Timer(_Ms, _Repeating)
8205  {
8206  _Initialize(_Value, _PTarget, _Repeating, &_Scheduler);
8207  }
8208 
8235 
8236  timer(ScheduleGroup& _ScheduleGroup, unsigned int _Ms, _Type const& _Value, _Inout_opt_ ITarget<_Type> *_PTarget = NULL, bool _Repeating = false) :
8237  _Timer(_Ms, _Repeating)
8238  {
8239  _Initialize(_Value, _PTarget, _Repeating, NULL, &_ScheduleGroup);
8240  }
8241 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
8242 
8246 
8248  {
8249  //
8250  // Make sure there are no more outstanding timer fires. Note that this does not mean that the LWT that was queued is finished, it only
8251  // means that no more timers will fire after the return from _Stop. We still *MUST* wait on any outstanding LWTs.
8252  //
8253  if (_M_state == Started)
8254  _Stop();
8255 
8256  // Remove all the targets. This will wait for any outstanding LWTs
8257  this->remove_targets();
8258 
8259  //
8260  // No more asynchronous operations can happen as of this point.
8261  //
8262 
8263  // Clean up any messages left in this message block
8265 
8267  {
8269  }
8270  }
8271 
8276 
8277  void start()
8278  {
8279  if (_M_state == Initialized || _M_state == Paused)
8280  {
8281  _M_state = Started;
8282  _Start();
8283  }
8284  }
8285 
8289 
8290  void stop()
8291  {
8292  if (_M_state == Started)
8293  _Stop();
8294 
8295  _M_state = Stopped;
8296  }
8297 
8302 
8303  void pause()
8304  {
8305  //
8306  // Non repeating timers cannot pause. They go to a final stopped state on pause.
8307  //
8308  if (!_M_fRepeating)
8309  {
8310  stop();
8311  }
8312  else
8313  {
8314  // Pause only a started timer.
8315 
8316  if (_M_state == Started)
8317  {
8318  _Stop();
8319  _M_state = Paused;
8320  }
8321  }
8322  }
8323 
8324 protected:
8325 
8336 
8337  virtual message<_Type> * accept_message(runtime_object_identity _MsgId)
8338  {
8339  if (_M_pMessage == NULL || _MsgId != _M_pMessage->msg_id())
8340  {
8341  return NULL;
8342  }
8343 
8344  message<_Type> *_PMessage = _M_pMessage;
8345  _M_pMessage = NULL;
8346 
8347  return _PMessage;
8348  }
8349 
8363 
8364  virtual bool reserve_message(runtime_object_identity _MsgId)
8365  {
8366  //
8367  // Semantically, every timer tick is the same value -- it doesn't matter the message ID. Because we can only
8368  // have one target as well, we do not need to track anything here.
8369  //
8370  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
8371  {
8372  return false;
8373  }
8374 
8375  return true;
8376  }
8377 
8391 
8392  virtual message<_Type> * consume_message(runtime_object_identity _MsgId)
8393  {
8394  return accept_message(_MsgId);
8395  }
8396 
8403 
8404  virtual void release_message(runtime_object_identity _MsgId)
8405  {
8406  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
8407  {
8408  throw message_not_found();
8409  }
8410 
8411  delete _M_pMessage;
8412  _M_pMessage = NULL;
8413  }
8414 
8418 
8419  virtual void resume_propagation()
8420  {
8421  // Because reservation doesn't prevent propagation there is
8422  // no need to resume on consume/release.
8423  }
8424 
8431 
8433  {
8434  // If there is a timer message sitting around, it must be propagated to the target now.
8435 
8436  if (_M_pMessage != NULL)
8437  {
8438  _PTarget->propagate(_M_pMessage, this);
8439  }
8440  }
8441 
8445 
8447  {
8448  if (_M_pMessage == NULL)
8449  {
8451  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
8452  {
8453  ITarget<_Type> * _PTarget = *_Iter;
8454  _PTarget->propagate(_M_pMessage, this);
8455  }
8456  }
8457  }
8458 
8459 private:
8460 
8461  // The timer message we contain
8463 
8464  // Current state of the timer.
8466 
8467  // The value to send on elapse of the timer.
8468  _Type _M_value;
8469 
8470  // An indication of whether the timer is repeating.
8472 
8473  // A flag for whether we need to release a reference on the scheduler.
8475 
8476  // Scheduler used for the timer
8477  Scheduler * _M_pScheduler;
8478 
8482 
8484  {
8485  return new message<_Type>(_M_value);
8486  }
8487 
8491 
8492  virtual void _Fire()
8493  {
8494  this->async_send(NULL);
8495  }
8496 
8509 
8510  void _Initialize(const _Type& _Value, _Inout_ ITarget<_Type> *_PTarget, bool _Repeating, _Inout_opt_ Scheduler * _PScheduler = NULL, _Inout_opt_ ScheduleGroup * _PScheduleGroup = NULL)
8511  {
8512  _M_pMessage = NULL;
8513  _M_value = _Value;
8514  _M_fRepeating = _Repeating;
8515  _M_state = Initialized;
8516  _M_fReferencedScheduler = false;
8517 
8518  //
8519  // If we are going to utilize the current scheduler for timer firing, we need to capture it now. Otherwise,
8520  // the timer threads fired from Windows (what _Fire executes within) will wind up with a default scheduler
8521  // attached -- probably not the semantic we want.
8522  //
8523  if (_PScheduleGroup == NULL && _PScheduler == NULL)
8524  {
8526  _PScheduler = _sched._GetScheduler();
8527  _sched._Reference();
8528  _M_fReferencedScheduler = true;
8529  }
8530 
8531  _M_pScheduler = _PScheduler;
8532  this->initialize_source(_PScheduler, _PScheduleGroup);
8533 
8534  if (_PTarget != NULL)
8535  {
8536  link_target(_PTarget);
8537  }
8538  }
8539 
8544 
8546  {
8547  // Input messages for this message block are in the base-class input buffer
8548  // All messages in that buffer are guaranteed to have moved to the output
8549  // buffer because the destructor first waits for all async sends to finish
8550  // before reaching this point
8551 
8552  // Delete the message remaining in the output queue
8553  if (_M_pMessage != NULL)
8554  {
8555  delete _M_pMessage;
8556  }
8557  }
8558 
8559 private:
8560  //
8561  // Hide assignment operator and copy constructor
8562  //
8563  timer const &operator =(timer const &); // no assignment operator
8564  timer(timer const &); // no copy constructor
8565 };
8566 
8567 //**************************************************************************
8568 // Single assignment:
8569 //**************************************************************************
8570 
8585 
8586 template<class _Type>
8587 class single_assignment : public propagator_block<multi_link_registry<ITarget<_Type>>, multi_link_registry<ISource<_Type>>>
8588 {
8589 private:
8592 
8593 public:
8597 
8610 
8613  {
8615  }
8616 
8632 
8635  {
8637  this->register_filter(_Filter);
8638  }
8639 
8640 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
8641 
8657  single_assignment(Scheduler& _PScheduler) :
8659  {
8660  this->initialize_source_and_target(&_PScheduler);
8661  }
8662 
8681 
8682  single_assignment(Scheduler& _PScheduler, filter_method const& _Filter) :
8684  {
8685  this->initialize_source_and_target(&_PScheduler);
8686  this->register_filter(_Filter);
8687  }
8688 
8705 
8706  single_assignment(ScheduleGroup& _PScheduleGroup) :
8708  {
8709  this->initialize_source_and_target(NULL, &_PScheduleGroup);
8710  }
8711 
8731 
8732  single_assignment(ScheduleGroup& _PScheduleGroup, filter_method const& _Filter) :
8734  {
8735  this->initialize_source_and_target(NULL, &_PScheduleGroup);
8736  this->register_filter(_Filter);
8737  }
8738 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
8739 
8743 
8745  {
8746  // Remove all links
8747  this->remove_network_links();
8748 
8749  // Clean up any messages left in this message block
8751  }
8752 
8759 
8760  bool has_value() const
8761  {
8762  return (_M_pMessage != NULL);
8763  }
8764 
8765 
8775 
8776  _Type const & value()
8777  {
8778  if (_M_pMessage == NULL)
8779  {
8780  ::Concurrency::receive<_Type>(this);
8781  }
8783 
8784  return _M_pMessage->payload;
8785  }
8786 
8787 
8788 protected:
8789 
8804 
8806  {
8807  // It is important that calls to propagate do *not* take the same lock on the
8808  // internal structure that is used by Consume and the LWT. Doing so could
8809  // result in a deadlock with the Consume call.
8810 
8811  message_status _Result = accepted;
8812 
8813  // single_assignment messaging block can be initialized only once
8814  if (_M_fIsInitialized)
8815  {
8816  return declined;
8817  }
8818 
8819  {
8820  _NR_lock _Lock(_M_propagationLock);
8821 
8822  if (_M_fIsInitialized)
8823  {
8824  _Result = declined;
8825  }
8826  else
8827  {
8828  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
8829 
8830  // Set initialized flag only if we have a message
8831  if (_PMessage != NULL)
8832  {
8833  _M_fIsInitialized = true;
8834  }
8835  else
8836  {
8837  _Result = missed;
8838  }
8839  }
8840  }
8841 
8842  //
8843  // If message was accepted, set the member variables for
8844  // this block and start the asynchronous propagation task
8845  //
8846  if (_Result == accepted)
8847  {
8848  this->async_send(_PMessage);
8849  }
8850 
8851  return _Result;
8852  }
8853 
8868 
8870  {
8871  message_status _Result = accepted;
8872 
8873  // single_assignment messaging block can be initialized only once
8874  if (_M_fIsInitialized)
8875  {
8876  return declined;
8877  }
8878 
8879  {
8880  _NR_lock _Lock(_M_propagationLock);
8881 
8882  if (_M_fIsInitialized)
8883  {
8884  _Result = declined;
8885  }
8886  else
8887  {
8888  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
8889 
8890  // Set initialized flag only if we have a message
8891  if (_PMessage != NULL)
8892  {
8893  _M_fIsInitialized = true;
8894  }
8895  else
8896  {
8897  _Result = missed;
8898  }
8899  }
8900  }
8901 
8902  //
8903  // If message was accepted, set the member variables for
8904  // this block and start the asynchronous propagation task
8905  //
8906  if (_Result == accepted)
8907  {
8908  this->sync_send(_PMessage);
8909  }
8910 
8911  return _Result;
8912  }
8913 
8929 
8930  virtual message<_Type> * accept_message(runtime_object_identity _MsgId)
8931  {
8932  // This check is to prevent spoofing and verify that the propagated message is
8933  // the one that is accepted at the end.
8934  if (_M_pMessage == NULL || _MsgId != _M_pMessage->msg_id())
8935  {
8936  return NULL;
8937  }
8938 
8939  //
8940  // Instead of returning the internal message, we return a copy of the
8941  // message passed in.
8942  //
8943  // Because we are returning a copy, the accept routine for a single_assignment
8944  // does not need to grab the internal lock.
8945  //
8946  return (new message<_Type>(_M_pMessage->payload));
8947  }
8948 
8962 
8963  virtual bool reserve_message(runtime_object_identity _MsgId)
8964  {
8965  if (_M_pMessage == NULL)
8966  {
8967  return false;
8968  }
8969 
8970  if (_M_pMessage->msg_id() != _MsgId)
8971  {
8972  throw message_not_found();
8973  }
8974 
8975  return true;
8976  }
8977 
8991 
8992  virtual message<_Type> * consume_message(runtime_object_identity _MsgId)
8993  {
8995 
8996  return accept_message(_MsgId);
8997  }
8998 
9005 
9006  virtual void release_message(runtime_object_identity _MsgId)
9007  {
9009 
9010  if (_M_pMessage == NULL || _M_pMessage->msg_id() != _MsgId)
9011  {
9012  throw message_not_found();
9013  }
9014  }
9015 
9019 
9020  virtual void resume_propagation()
9021  {
9022  // Because reservation doesn't stop propagation, we don't
9023  // need to do anything on resume after consume/release.
9024  }
9025 
9032 
9034  {
9035  // If there is a message available already, propagate it.
9036 
9037  if (_M_pMessage != NULL)
9038  {
9039  _PTarget->propagate(_M_pMessage, this);
9040  }
9041  }
9049 
9051  {
9052  // Initialized flag should have been set by the propagate function using interlocked operation.
9054 
9055  // Move the message to the internal storage
9056 
9058  _M_pMessage = _PMessage;
9059 
9060  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
9061  {
9062  // Single assignment can propagate its message out
9063  // to any number of Targets
9064 
9065  ITarget<_Type> * _PTarget = *_Iter;
9066  _PTarget->propagate(_PMessage, this);
9067  }
9068  }
9069 
9070 private:
9071 
9076 
9078  {
9079  // Input messages for this message block are in the base-class input buffer
9080  // All messages in that buffer are guaranteed to have moved to the output
9081  // buffer because the destructor first waits for all async sends to finish
9082  // before reaching this point
9083 
9084  // The messages for a single_assignment are deleted at the end when
9085  // single_assignment is deleted.
9086  delete _M_pMessage;
9087  }
9088 
9089  //
9090  // Private Data Members
9091  //
9092 
9093  // The message being stored
9095 
9096  // The lock used to protect propagation
9098 
9099  // The marker for whether the single_assignment has already been initialized
9100  volatile bool _M_fIsInitialized;
9101 
9102 private:
9103  //
9104  // Hide assignment operator and copy constructor
9105  //
9106  single_assignment const & operator=(single_assignment const &); // no assignment operator
9107  single_assignment(single_assignment const &); // no copy constructor
9108 };
9109 
9110 //**************************************************************************
9111 // Join (single-type)
9112 //**************************************************************************
9113 
9117 
9123 
9124  greedy = 0,
9129 
9131 };
9132 
9150 
9151 template<class _Type, join_type _Jtype = non_greedy>
9152 class join : public propagator_block<single_link_registry<ITarget<std::vector<_Type>>>, multi_link_registry<ISource<_Type>>>
9153 {
9154 private:
9157 
9158 public:
9163 
9164  typedef typename std::vector<_Type> _OutputType;
9165 
9181 
9182  join(size_t _NumInputs)
9183  : _M_messageArray(_NumInputs),
9184  _M_savedMessageIdArray(_NumInputs)
9185  {
9186  _Initialize(_NumInputs);
9187  }
9188 
9207 
9208  join(size_t _NumInputs, filter_method const& _Filter)
9209  : _M_messageArray(_NumInputs),
9210  _M_savedMessageIdArray(_NumInputs)
9211  {
9212  _Initialize(_NumInputs);
9213  register_filter(_Filter);
9214  }
9215 
9216 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
9217 
9236  join(Scheduler& _PScheduler, size_t _NumInputs)
9237  : _M_messageArray(_NumInputs),
9238  _M_savedMessageIdArray(_NumInputs)
9239  {
9240  _Initialize(_NumInputs, &_PScheduler);
9241  }
9242 
9264 
9265  join(Scheduler& _PScheduler, size_t _NumInputs, filter_method const& _Filter)
9266  : _M_messageArray(_NumInputs),
9267  _M_savedMessageIdArray(_NumInputs)
9268  {
9269  _Initialize(_NumInputs, &_PScheduler);
9270  register_filter(_Filter);
9271  }
9272 
9292 
9293  join(ScheduleGroup& _PScheduleGroup, size_t _NumInputs)
9294  : _M_messageArray(_NumInputs),
9295  _M_savedMessageIdArray(_NumInputs)
9296  {
9297  _Initialize(_NumInputs, NULL, &_PScheduleGroup);
9298  }
9299 
9322 
9323  join(ScheduleGroup& _PScheduleGroup, size_t _NumInputs, filter_method const& _Filter)
9324  : _M_messageArray(_NumInputs),
9325  _M_savedMessageIdArray(_NumInputs)
9326  {
9327  _Initialize(_NumInputs, NULL, &_PScheduleGroup);
9328  register_filter(_Filter);
9329  }
9330 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
9331 
9335 
9337  {
9338  // Remove all links that are targets of this join
9339  this->remove_network_links();
9340 
9341  // Clean up any messages left in this message block
9343 
9344  delete [] _M_savedIdBuffer;
9345  }
9346 
9347 protected:
9348  //
9349  // propagator_block protected function implementations
9350  //
9351 
9366 
9368  {
9369  // It is important that calls to propagate do *not* take the same lock on the
9370  // internal structure that is used by Consume and the LWT. Doing so could
9371  // result in a deadlock with the Consume call.
9372 
9373  message_status _Ret_val = accepted;
9374 
9375  //
9376  // Find the slot index of this source
9377  //
9378  size_t _Slot = 0;
9379  bool _Found = false;
9380  for (source_iterator _Iter = this->_M_connectedSources.begin(); *_Iter != NULL; ++_Iter)
9381  {
9382  if (*_Iter == _PSource)
9383  {
9384  _Found = true;
9385  break;
9386  }
9387 
9388  _Slot++;
9389  }
9390 
9391  if (!_Found)
9392  {
9393  // If this source was not found in the array, this is not a connected source
9394  // decline the message
9395  return declined;
9396  }
9397 
9399 
9400  bool fIsGreedy = (_Jtype == greedy);
9401 
9402  if (fIsGreedy)
9403  {
9404  //
9405  // Greedy type joins immediately accept the message.
9406  //
9407  {
9408  _NR_lock lockHolder(_M_propagationLock);
9409  if (_M_messageArray._M_messages[_Slot] != NULL)
9410  {
9411  _M_savedMessageIdArray._M_savedIds[_Slot] = _PMessage->msg_id();
9412  _Ret_val = postponed;
9413  }
9414  }
9415 
9416  if (_Ret_val != postponed)
9417  {
9418  _M_messageArray._M_messages[_Slot] = _PSource->accept(_PMessage->msg_id(), this);
9419 
9420  if (_M_messageArray._M_messages[_Slot] != NULL)
9421  {
9423  {
9424  // If messages have arrived on all links, start a propagation
9425  // of the current message
9426  this->async_send(NULL);
9427  }
9428  }
9429  else
9430  {
9431  _Ret_val = missed;
9432  }
9433  }
9434  }
9435  else
9436  {
9437  //
9438  // Non-greedy type joins save the message IDs until they have all arrived
9439  //
9440 
9441  if (_InterlockedExchange((volatile long *) &_M_savedMessageIdArray._M_savedIds[_Slot], _PMessage->msg_id()) == -1)
9442  {
9443  // Decrement the message remaining count if this thread is switching
9444  // the saved ID from -1 to a valid value.
9446  {
9447  this->async_send(NULL);
9448  }
9449  }
9450 
9451  // Always return postponed. This message will be consumed
9452  // in the LWT
9453  _Ret_val = postponed;
9454  }
9455 
9456  return _Ret_val;
9457  }
9458 
9469 
9470  virtual message<_OutputType> * accept_message(runtime_object_identity _MsgId)
9471  {
9472  //
9473  // Peek at the head message in the message buffer. If the IDs match
9474  // dequeue and transfer ownership
9475  //
9476  message<_OutputType> * _Msg = NULL;
9477 
9478  if (_M_messageBuffer._Is_head(_MsgId))
9479  {
9480  _Msg = _M_messageBuffer._Dequeue();
9481  }
9482 
9483  return _Msg;
9484  }
9485 
9499 
9500  virtual bool reserve_message(runtime_object_identity _MsgId)
9501  {
9502  // Allow reservation if this is the head message
9503  return _M_messageBuffer._Is_head(_MsgId);
9504  }
9505 
9519 
9520  virtual message<_OutputType> * consume_message(runtime_object_identity _MsgId)
9521  {
9522  // By default, accept the message
9523  return accept_message(_MsgId);
9524  }
9525 
9532 
9533  virtual void release_message(runtime_object_identity _MsgId)
9534  {
9535  // The head message is the one reserved.
9536  if (!_M_messageBuffer._Is_head(_MsgId))
9537  {
9538  throw message_not_found();
9539  }
9540  }
9541 
9545 
9546  virtual void resume_propagation()
9547  {
9548  // If there are any messages in the buffer, propagate them out
9549  if (_M_messageBuffer._Count() > 0)
9550  {
9551  this->async_send(NULL);
9552  }
9553  }
9554 
9561 
9562  virtual void link_target_notification(_Inout_ ITarget<std::vector<_Type>> *)
9563  {
9564  // If the message queue is blocked due to reservation
9565  // there is no need to do any message propagation
9566  if (this->_M_pReservedFor != NULL)
9567  {
9568  return;
9569  }
9570 
9572  }
9573 
9579 
9581  {
9582  message<_OutputType> * _Msg = NULL;
9583  // Create a new message from the input sources
9584  // If messagesRemaining == 0, we have a new message to create. Otherwise, this is coming from
9585  // a consume or release from the target. In that case we don't want to create a new message.
9586  if (_M_messagesRemaining == 0)
9587  {
9588  // A greedy join can immediately create the message, a non-greedy
9589  // join must try and consume all the messages it has postponed
9590  _Msg = _Create_new_message();
9591  }
9592 
9593  if (_Msg == NULL)
9594  {
9595  // Create message failed. This happens in non_greedy joins when the
9596  // reserve/consumption of a postponed message failed.
9598  return;
9599  }
9600 
9601  bool fIsGreedy = (_Jtype == greedy);
9602 
9603  // For a greedy join, reset the number of messages remaining
9604  // Check to see if multiple messages have been passed in on any of the links,
9605  // and postponed. If so, try and reserve/consume them now
9606  if (fIsGreedy)
9607  {
9608  // Look at the saved IDs and reserve/consume any that have passed in while
9609  // this join was waiting to complete
9611 
9612  for (size_t i = 0; i < _M_messageArray._M_count; i++)
9613  {
9614  for(;;)
9615  {
9616  runtime_object_identity _Saved_id;
9617  // Grab the current saved ID value. This value could be changing from based on any
9618  // calls of source->propagate(this). If the message ID is different than what is snapped
9619  // here, that means, the reserve below must fail. This is because reserve is trying
9620  // to get the same source lock the propagate(this) call must be holding.
9621  {
9622  _NR_lock lockHolder(_M_propagationLock);
9623 
9625 
9626  _Saved_id = _M_savedMessageIdArray._M_savedIds[i];
9627 
9628  if (_Saved_id == -1)
9629  {
9631  break;
9632  }
9633  else
9634  {
9636  }
9637  }
9638 
9639  if (_Saved_id != -1)
9640  {
9641  source_iterator _Iter = this->_M_connectedSources.begin();
9642 
9643  ISource<_Type> * _PSource = _Iter[i];
9644  if ((_PSource != NULL) && _PSource->reserve(_Saved_id, this))
9645  {
9646  _M_messageArray._M_messages[i] = _PSource->consume(_Saved_id, this);
9648  break;
9649  }
9650  }
9651  }
9652  }
9653 
9654  // If messages have all been received, async_send again, this will start the
9655  // LWT up to create a new message
9656  if (_M_messagesRemaining == 0)
9657  {
9658  this->async_send(NULL);
9659  }
9660  }
9661 
9662  // Add the new message to the outbound queue
9663  _M_messageBuffer._Enqueue(_Msg);
9664 
9665  if (!_M_messageBuffer._Is_head(_Msg->msg_id()))
9666  {
9667  // another message is at the head of the outbound message queue and blocked
9668  // simply return
9669  return;
9670  }
9671 
9673  }
9674 
9675 private:
9676 
9677  //
9678  // Private Methods
9679  //
9680 
9687 
9689  {
9690  message<_Target_type> * _Msg = _MessageBuffer._Peek();
9691 
9692  // If someone has reserved the _Head message, don't propagate anymore
9693  if (this->_M_pReservedFor != NULL)
9694  {
9695  return;
9696  }
9697 
9698  while (_Msg != NULL)
9699  {
9700  message_status _Status = declined;
9701 
9702  // Always start from the first target that linked
9703  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
9704  {
9705  ITarget<_Target_type> * _PTarget = *_Iter;
9706  _Status = _PTarget->propagate(_Msg, this);
9707 
9708  // Ownership of message changed. Do not propagate this
9709  // message to any other target.
9710  if (_Status == accepted)
9711  {
9712  break;
9713  }
9714 
9715  // If the target just propagated to reserved this message, stop
9716  // propagating it to others
9717  if (this->_M_pReservedFor != NULL)
9718  {
9719  break;
9720  }
9721  }
9722 
9723  // If status is anything other than accepted, then the head message
9724  // was not propagated out. Thus, nothing after it in the queue can
9725  // be propagated out. Cease propagation.
9726  if (_Status != accepted)
9727  {
9728  break;
9729  }
9730 
9731  // Get the next message
9732  _Msg = _MessageBuffer._Peek();
9733  }
9734  }
9735 
9742 
9744  {
9745  bool fIsNonGreedy = (_Jtype == non_greedy);
9746 
9747  // If this is a non-greedy join, check each source and try to consume their message
9748  if (fIsNonGreedy)
9749  {
9750 
9751  // The iterator _Iter below will ensure that it is safe to touch
9752  // non-NULL source pointers. Take a snapshot.
9753  std::vector<ISource<_Type> *> _Sources;
9754  source_iterator _Iter = this->_M_connectedSources.begin();
9755 
9756  while (*_Iter != NULL)
9757  {
9758  ISource<_Type> * _PSource = *_Iter;
9759 
9760  if (_PSource == NULL)
9761  {
9762  break;
9763  }
9764 
9765  _Sources.push_back(_PSource);
9766  ++_Iter;
9767  }
9768 
9769  if (_Sources.size() != _M_messageArray._M_count)
9770  {
9771  // Some of the sources were unlinked. The join is broken
9772  return NULL;
9773  }
9774 
9775  // First, try and reserve all the messages. If a reservation fails,
9776  // then release any reservations that had been made.
9777  for (size_t i = 0; i < _M_savedMessageIdArray._M_count; i++)
9778  {
9779  // Snap the current saved ID into a buffer. This value can be changing behind the scenes from
9780  // other source->propagate(msg, this) calls, but if so, that just means the reserve below will
9781  // fail.
9783  _M_savedIdBuffer[i] = _InterlockedExchange((volatile long *) &_M_savedMessageIdArray._M_savedIds[i], -1);
9784 
9786 
9787  if (!_Sources[i]->reserve(_M_savedIdBuffer[i], this))
9788  {
9789  // A reservation failed, release all reservations made up until
9790  // this block, and wait for another message to arrive on this link
9791  for (size_t j = 0; j < i; j++)
9792  {
9793  _Sources[j]->release(_M_savedIdBuffer[j], this);
9794  if (_InterlockedCompareExchange((volatile long *) &_M_savedMessageIdArray._M_savedIds[j], _M_savedIdBuffer[j], -1) == -1)
9795  {
9797  {
9798  this->async_send(NULL);
9799  }
9800  }
9801  }
9802 
9803  // Return NULL to indicate that the create failed
9804  return NULL;
9805  }
9806  }
9807 
9808  // Because everything has been reserved, consume all the messages.
9809  // This is guaranteed to return true.
9810  for (size_t i = 0; i < _M_messageArray._M_count; i++)
9811  {
9812  _M_messageArray._M_messages[i] = _Sources[i]->consume(_M_savedIdBuffer[i], this);
9813  _M_savedIdBuffer[i] = -1;
9814  }
9815  }
9816 
9817  if (!fIsNonGreedy)
9818  {
9819  // Reinitialize how many messages are being waited for.
9820  // This is safe because all messages have been received, thus no new async_sends for
9821  // greedy joins can be called.
9823  }
9824 
9825  std::vector<_Type> _OutputVector;
9826  for (size_t i = 0; i < _M_messageArray._M_count; i++)
9827  {
9829  _OutputVector.push_back(_M_messageArray._M_messages[i]->payload);
9830 
9831  delete _M_messageArray._M_messages[i];
9832  if (fIsNonGreedy)
9833  {
9835  }
9836  }
9837  return (new message<std::vector<_Type>>(_OutputVector));
9838  }
9839 
9855 
9856  void _Initialize(size_t _NumInputs, Scheduler * _PScheduler = NULL, ScheduleGroup * _PScheduleGroup = NULL)
9857  {
9858  this->initialize_source_and_target(_PScheduler, _PScheduleGroup);
9859 
9860  this->_M_connectedSources.set_bound(_NumInputs);
9861  _M_messagesRemaining = _NumInputs;
9862 
9863  bool fIsNonGreedy = (_Jtype == non_greedy);
9864 
9865  if (fIsNonGreedy)
9866  {
9867  // Non greedy joins need a buffer to snap off saved message IDs to.
9868  _M_savedIdBuffer = new runtime_object_identity[_NumInputs];
9869  memset(_M_savedIdBuffer, -1, sizeof(runtime_object_identity) * _NumInputs);
9870  }
9871  else
9872  {
9874  }
9875  }
9876 
9881 
9883  {
9884  // Input messages for this message block are in the base-class input buffer
9885  // All messages in that buffer are guaranteed to have moved to the output
9886  // buffer because the destructor first waits for all async sends to finish
9887  // before reaching this point
9888 
9889  // Delete any messages remaining in the output queue
9890  for (;;)
9891  {
9892  message<std::vector<_Type>> * _Msg = _M_messageBuffer._Dequeue();
9893  if (_Msg == NULL)
9894  {
9895  break;
9896  }
9897  delete _Msg;
9898  }
9899  }
9900 
9901  // The current number of messages remaining
9902  volatile size_t _M_messagesRemaining;
9903 
9904  // An array containing the accepted messages of this join.
9905  // Wrapped in a struct to enable debugger visualization.
9907  {
9908  size_t _M_count;
9910 
9911  _MessageArray(size_t _NumInputs)
9912  : _M_count(_NumInputs),
9913  _M_messages(new message<_Type>*[_NumInputs])
9914  {
9915  memset(_M_messages, 0, sizeof(message<_Type> *) * _NumInputs);
9916  }
9917 
9919  {
9920  for (size_t i = 0; i < _M_count; i++)
9921  delete _M_messages[i];
9922  delete [] _M_messages;
9923  }
9924  };
9926 
9927  // An array containing the msg IDs of messages propagated to the array
9928  // For greedy joins, this contains a log of other messages passed to this
9929  // join after the first has been accepted
9930  // For non-greedy joins, this contains the message ID of any message
9931  // passed to it.
9932  // Wrapped in a struct to enable debugger visualization.
9934  {
9935  size_t _M_count;
9936  runtime_object_identity * _M_savedIds;
9937 
9938  _SavedMessageIdArray(size_t _NumInputs)
9939  : _M_count(_NumInputs),
9940  _M_savedIds(new runtime_object_identity[_NumInputs])
9941  {
9942  memset(_M_savedIds, -1, sizeof(runtime_object_identity) * _NumInputs);
9943  }
9944 
9946  {
9947  delete [] _M_savedIds;
9948  }
9949  };
9951 
9952  // Buffer for snapping saved IDs in non-greedy joins
9953  runtime_object_identity * _M_savedIdBuffer;
9954 
9955  // A lock for modifying the buffer or the connected blocks
9957 
9958  // Queue to hold output messages
9960 };
9961 
9962 
9963 //**************************************************************************
9964 // Multi-Type Choice and Join helper node:
9965 //**************************************************************************
9966 
9976 
9977 template<class _Type>
9978 class _Order_node_base: public propagator_block<single_link_registry<ITarget<size_t>>, multi_link_registry<ISource<_Type>>>
9979 {
9980 public:
9985 
9987  _M_index(0),
9990  {
9991  }
9992 
9996 
9998  {
9999  // The messages for an _Order_node_base are deleted at the end when
10000  // _Order_node_base is deleted.
10001  delete _M_pReceiveMessage;
10002  delete _M_pSendMessage;
10003  }
10004 
10011 
10012  bool has_value() const
10013  {
10014  return (_M_pReceiveMessage != NULL);
10015  }
10016 
10023 
10024  _Type const & value()
10025  {
10027 
10028  return _M_pReceiveMessage->payload;
10029  }
10030 
10039 
10040  virtual void _Reset() = 0;
10041 
10054 
10055  virtual bool reserve_message(runtime_object_identity)
10056  {
10057  // reserve should never be called for this block.
10058  _CONCRT_ASSERT(false);
10059 
10060  return false;
10061  }
10062 
10076 
10077  virtual message<size_t> * consume_message(runtime_object_identity)
10078  {
10079  // consume should never be called for this block.
10080  _CONCRT_ASSERT(false);
10081 
10082  return NULL;
10083  }
10084 
10091 
10092  virtual void release_message(runtime_object_identity)
10093  {
10094  // release should never be called for this block.
10095  _CONCRT_ASSERT(false);
10096  }
10097 
10098 protected:
10099 
10100 
10104 
10105  virtual void resume_propagation()
10106  {
10107  // Because there is only a single target, nothing needs
10108  // to be done on resume
10109  }
10110 
10117 
10119  {
10120  if (_M_pSendMessage != NULL)
10121  {
10123  }
10124  }
10125 
10129 
10131  {
10133  }
10134 
10138 
10139  void _Initialize_order_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, Scheduler * _PScheduler = NULL, ScheduleGroup * _PScheduleGroup = NULL)
10140  {
10141  if (_PSource == NULL)
10142  {
10143  throw std::invalid_argument("_PSource");
10144  }
10145 
10146  _M_index = _Index;
10147 
10148  this->initialize_source_and_target(_PScheduler, _PScheduleGroup);
10149 
10150  // Allow only a single source and ensure that they
10151  // cannot be unlinked and relinked.
10152  this->_M_connectedSources.set_bound(1);
10153 
10154  if (_PTarget != NULL)
10155  {
10156  this->link_target(_PTarget);
10157  }
10158 
10159  _PSource->link_target(this);
10160  }
10161 
10162  //
10163  // Private Data Members
10164  //
10165 
10166  // The message to be received from the source
10168 
10169  // The message to be sent to all targets
10171 
10172  // The index of the _Order_node_base in the user's construct
10173  size_t _M_index;
10174 
10175 private:
10176  //
10177  // Hide assignment operator and copy constructor
10178  //
10179  _Order_node_base const & operator=(_Order_node_base const &); // no assignment operator
10180  _Order_node_base(_Order_node_base const &); // no copy constructor
10181 };
10182 
10183 
10192 
10193 template<class _Type>
10194 class _Reserving_node: public _Order_node_base<_Type>
10195 {
10196 private:
10199 
10200 public:
10205 
10219 
10220  _Reserving_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10222  _M_savedId(-1),
10224  {
10225  _Initialize_order_node(_PSource, _Index, _PTarget);
10226  }
10227 
10244 
10245  _Reserving_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10247  _M_savedId(-1),
10249  {
10250  register_filter(_Filter);
10251  _Initialize_order_node(_PSource, _Index, _PTarget);
10252  }
10253 
10270 
10271  _Reserving_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10273  _M_savedId(-1),
10275  {
10276  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
10277  }
10278 
10298 
10299  _Reserving_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10301  _M_savedId(-1),
10303  {
10304  register_filter(_Filter);
10305  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
10306  }
10307 
10324 
10325  _Reserving_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10327  _M_savedId(-1),
10329  {
10330  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
10331  }
10332 
10352 
10353  _Reserving_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10355  _M_savedId(-1),
10357  {
10358  register_filter(_Filter);
10359  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
10360  }
10361 
10365 
10367  {
10368  if (_M_pReservedSource != NULL)
10369  {
10371  this->_M_connectedSources.release();
10372  }
10373 
10374  // Remove all links
10375  this->remove_network_links();
10376  }
10377 
10378 
10385 
10386  virtual void _Reset()
10387  {
10388  }
10389 
10390 protected:
10391 
10392  //
10393  // propagator_block protected function implementation
10394  //
10395 
10415 
10417  {
10418  message_status _Result = postponed;
10419 
10420  // _Order_node messaging block can be initialized only once, just like single_assignment.
10421  if (_M_fIsInitialized)
10422  {
10423  return declined;
10424  }
10425 
10426  // Reserve a message on the source until this _Order_node gets the feedback from
10427  // the single_assignment on whether it has been selected.
10428  _M_fIsInitialized = _PSource->reserve(_PMessage->msg_id(), this);
10429 
10430  //
10431  // If message was successfully reserved, set the member variables for
10432  // this messaging block and start the asynchronous propagation task.
10433  //
10434  if (_M_fIsInitialized)
10435  {
10436  _M_savedId = _PMessage->msg_id();
10437  this->async_send(NULL);
10438  }
10439  else
10440  {
10441  _Result = missed;
10442  }
10443 
10444  return _Result;
10445  }
10446 
10456 
10457  virtual message<size_t> * accept_message(runtime_object_identity _MsgId)
10458  {
10459  // This check is to prevent spoofing and verify that the propagated message is
10460  // the one that is accepted at the end.
10461  if (this->_M_pSendMessage == NULL || _MsgId != this->_M_pSendMessage->msg_id())
10462  {
10463  return NULL;
10464  }
10465 
10466  // If the source has disconnected then we can't allow for accept to succeed.
10467  source_iterator _Iter = this->_M_connectedSources.begin();
10468  ISource<_Type>* _PSource = *_Iter;
10469 
10470  if (_PSource == NULL)
10471  {
10472  // source was disconnected. Fail accept.
10473  return NULL;
10474  }
10475 
10476  this->_M_pReceiveMessage = _PSource->consume(_M_savedId, this);
10477 
10479 
10480  //
10481  // Instead of returning the internal message, we return a copy of the
10482  // message passed in.
10483  //
10484  // Because we are returning a copy, the accept routine for a _Order_node
10485  // does not need to grab the internal lock.
10486  //
10487  return (new message<size_t>(this->_M_pSendMessage->payload));
10488  }
10489 
10499 
10501  {
10502  if (this->_M_pSendMessage == NULL)
10503  {
10504  this->_Create_send_message();
10505  }
10506 
10507  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
10508  {
10509  ITarget<size_t> * _PTarget = *_Iter;
10510  _Propagate_to_target(_PTarget);
10511  }
10512  }
10513 
10514 private:
10515 
10519 
10521  {
10522  message_status _Status = _PTarget->propagate(this->_M_pSendMessage, this);
10523 
10524  // If the message got rejected we have to release the hold on the source message.
10525  if (_Status != accepted)
10526  {
10527  if (_M_savedId != -1)
10528  {
10529  // Release the reservation
10530  source_iterator _Iter = this->_M_connectedSources.begin();
10531  ISource<_Type> * _PSource = *_Iter;
10532 
10533  if (_PSource != NULL)
10534  {
10535  _PSource->release(_M_savedId, this);
10536  }
10537 
10538  // If the source was disconnected, then it would
10539  // automatically release any reservation. So we
10540  // should reset our savedId regardless.
10541  _M_savedId = -1;
10542  }
10543 
10544  }
10545 
10546  return _Status;
10547  }
10548 
10549  //
10550  // Private Data Members
10551  //
10552 
10553  // The source where we have reserved a message
10555 
10556  // For greedy order-nodes, the message ID of subsequent messages sent to this node
10557  // For non-greedy order nodes, the message ID of the message to reserve/consume
10558  runtime_object_identity _M_savedId;
10559 
10560  // The marker that indicates that _Reserving_node has reserved a message
10561  volatile bool _M_fIsInitialized;
10562 
10563 private:
10564  //
10565  // Hide assignment operator and copy constructor
10566  //
10567  _Reserving_node const & operator=(_Reserving_node const &); // no assignment operator
10568  _Reserving_node(_Reserving_node const &); // no copy constructor
10569 };
10570 
10571 
10580 
10581 template<class _Type>
10582 class _Greedy_node: public _Order_node_base<_Type>
10583 {
10584 private:
10587 
10588 public:
10593 
10607 
10608  _Greedy_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10609  _M_savedId(-1),
10611  {
10612  _Initialize_order_node(_PSource, _Index, _PTarget);
10613  }
10614 
10631 
10632  _Greedy_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10633  _M_savedId(-1),
10635  {
10636  register_filter(_Filter);
10637  _Initialize_order_node(_PSource, _Index, _PTarget);
10638  }
10639 
10656 
10657  _Greedy_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10658  _M_savedId(-1),
10660  {
10661  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
10662  }
10663 
10683 
10684  _Greedy_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10685  _M_savedId(-1),
10687  {
10688  register_filter(_Filter);
10689  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
10690  }
10691 
10708 
10709  _Greedy_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
10710  _M_savedId(-1),
10712  {
10713  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
10714  }
10715 
10735 
10736  _Greedy_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
10737  _M_savedId(-1),
10739  {
10740  register_filter(_Filter);
10741  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
10742  }
10743 
10747 
10749  {
10750  // Remove all links
10751  this->remove_network_links();
10752 
10754  {
10755  delete _M_pGreedyMessage;
10756  }
10757  }
10758 
10766 
10767  void _Reset()
10768  {
10769  _R_lock _Lock(_M_resetLock);
10770 
10771  delete this->_M_pReceiveMessage;
10772  this->_M_pReceiveMessage = NULL;
10773 
10774  delete this->_M_pSendMessage;
10775  this->_M_pSendMessage = NULL;
10776 
10777  //
10778  // For greedy type joins, look to see if any other messages have been
10779  // passed to this _Greedy_node while the join was waiting for other
10780  // messages to arrive. This function is already called with _M_resetLock
10781  // held through propagate_to_any_targets().
10782  //
10783  for(;;)
10784  {
10785  // Set the current saved ID as -1. Check to see if something was ready for consumption
10786  // (if _Saved_id != -1) and consume it if possible.
10787  runtime_object_identity _Saved_id;
10788 
10789  {
10790  _NR_lock lockHolder(_M_propagationLock);
10791 
10792  _Saved_id = _M_savedId;
10793 
10794  if (_Saved_id == -1)
10795  {
10797  break;
10798  }
10799  else
10800  {
10801  _M_savedId = -1;
10802  }
10803  }
10804 
10805  if (_Saved_id != -1)
10806  {
10807  source_iterator _Iter = this->_M_connectedSources.begin();
10808 
10809  ISource<_Type> * _PSource = *_Iter;
10810  if ((_PSource != NULL) && _PSource->reserve(_Saved_id, this))
10811  {
10812  _M_pGreedyMessage = _PSource->consume(_Saved_id, this);
10813  this->async_send(NULL);
10814  break;
10815  }
10816  }
10817  }
10818  }
10819 
10820 protected:
10821 
10822  //
10823  // propagator_block protected function implementation
10824  //
10825 
10845 
10847  {
10848  message_status _Result = postponed;
10849 
10850  bool _FDone = false;
10851 
10852  {
10853  _NR_lock lockHolder(_M_propagationLock);
10854  if (_M_pGreedyMessage != NULL)
10855  {
10856  _M_savedId = _PMessage->msg_id();
10857  _Result = postponed;
10858  _FDone = true;
10859  }
10860  }
10861 
10862  if (!_FDone)
10863  {
10864  _M_pGreedyMessage = _PSource->accept(_PMessage->msg_id(), this);
10865 
10866  if (_M_pGreedyMessage != NULL)
10867  {
10868  _Result = accepted;
10869  this->async_send(NULL);
10870  }
10871  else
10872  {
10873  _Result = missed;
10874  }
10875  }
10876 
10877  return _Result;
10878  }
10879 
10889 
10890  virtual message<size_t> * accept_message(runtime_object_identity _MsgId)
10891  {
10892  // This check is to prevent spoofing and verify that the propagated message is
10893  // the one that is accepted at the end.
10894  if (this->_M_pSendMessage == NULL || _MsgId != this->_M_pSendMessage->msg_id())
10895  {
10896  return NULL;
10897  }
10898 
10899  //
10900  // Instead of returning the internal message, we return a copy of the
10901  // message passed in.
10902  //
10903  // Because we are returning a copy, the accept routine for a _Greedy_node
10904  // does not need to grab the internal lock.
10905  //
10906  return (new message<size_t>(this->_M_pSendMessage->payload));
10907  }
10908 
10909 
10919 
10921  {
10922  _R_lock _Lock(_M_resetLock);
10923 
10924  if (this->_M_pSendMessage == NULL)
10925  {
10926  // Save the incoming message so that it can be consumed in the accept function
10928  this->_Create_send_message();
10929  }
10930 
10931  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
10932  {
10933  ITarget<size_t> * _PTarget = *_Iter;
10934  _PTarget->propagate(this->_M_pSendMessage, this);
10935  }
10936  }
10937 
10938 private:
10939 
10940  //
10941  // Private Data Members
10942  //
10943 
10944  // The message to be saved by a greedy order node
10946 
10947  // The lock used to protect propagation
10949 
10950  // The lock used to protect modification during a reset
10952 
10953  // For greedy order-nodes, the message ID of subsequent messages sent to this node
10954  // For non-greedy order nodes, the message ID of the message to reserve/consume
10955  runtime_object_identity _M_savedId;
10956 
10957 private:
10958  //
10959  // Hide assignment operator and copy constructor
10960  //
10961  _Greedy_node const & operator=(_Greedy_node const &); // no assignment operator
10962  _Greedy_node(_Greedy_node const &); // no copy constructor
10963 };
10964 
10965 
10974 
10975 template<class _Type>
10977 {
10978 private:
10981 
10982 public:
10987 
11001 
11002  _Non_greedy_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
11003  _M_savedId(-1),
11004  _M_reservedId(-1),
11006  {
11007  _Initialize_order_node(_PSource, _Index, _PTarget);
11008  }
11009 
11026 
11027  _Non_greedy_node(ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
11028  _M_savedId(-1),
11029  _M_reservedId(-1),
11031  {
11032  register_filter(_Filter);
11033  _Initialize_order_node(_PSource, _Index, _PTarget);
11034  }
11035 
11052 
11053  _Non_greedy_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
11054  _M_savedId(-1),
11055  _M_reservedId(-1),
11057  {
11058  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
11059  }
11060 
11080 
11081  _Non_greedy_node(Scheduler& _PScheduler, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
11082  _M_savedId(-1),
11083  _M_reservedId(-1),
11085  {
11086  register_filter(_Filter);
11087  _Initialize_order_node(_PSource, _Index, _PTarget, &_PScheduler);
11088  }
11089 
11106 
11107  _Non_greedy_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget = NULL) :
11108  _M_savedId(-1),
11109  _M_reservedId(-1),
11111  {
11112  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
11113  }
11114 
11134 
11135  _Non_greedy_node(ScheduleGroup& _PScheduleGroup, ISource<_Type> * _PSource, size_t _Index, ITarget<size_t> * _PTarget, filter_method const& _Filter) :
11136  _M_savedId(-1),
11137  _M_reservedId(-1),
11139  {
11140  register_filter(_Filter);
11141  _Initialize_order_node(_PSource, _Index, _PTarget, NULL, &_PScheduleGroup);
11142  }
11143 
11147 
11149  {
11150  if (_M_pReservedSource != NULL)
11151  {
11153  this->_M_connectedSources.release();
11154  }
11155 
11156  // Remove all links
11157  this->remove_network_links();
11158  }
11159 
11167 
11168  void _Reset()
11169  {
11170  _R_lock _Lock(_M_resetLock);
11171 
11172  delete this->_M_pReceiveMessage;
11173  this->_M_pReceiveMessage = NULL;
11174 
11175  delete this->_M_pSendMessage;
11176  this->_M_pSendMessage = NULL;
11177  }
11178 
11186 
11188  {
11189  bool _Ret_val = false;
11190 
11191  // Order node has only a single source.
11192  // Obtain an iterator to the first source. It will guarantee that the reference
11193  // count on the source is maintained
11194  source_iterator _Iter = this->_M_connectedSources.begin();
11195  ISource<_Type> * _PSource = *_Iter;
11196 
11197  if (_PSource != NULL)
11198  {
11199  // CAS out the current saved ID, in order to try and reserve it
11200  runtime_object_identity _SavedId = _InterlockedExchange((volatile long *) &_M_savedId, -1);
11201 
11202  _Ret_val = _PSource->reserve(_SavedId, this);
11203  //
11204  // If this reserved failed, that means we need to wait for another message
11205  // to come in on this link. _M_savedID was set to -1 to indicate to the _Order_node
11206  // that it needs to async_send when that next message comes through
11207  //
11208  // If the reserve succeeds, save away the reserved ID. This will be use later in
11209  // consume
11210  //
11211  if (_Ret_val)
11212  {
11213  _M_reservedId = _SavedId;
11214 
11215  // Acquire a reference on the source
11217  _M_pReservedSource = _PSource;
11218  }
11219  }
11220 
11221  return _Ret_val;
11222  }
11223 
11228 
11230  {
11231  if (_M_pReservedSource != NULL)
11232  {
11233  runtime_object_identity _SavedId = _M_reservedId;
11234  this->_M_pReceiveMessage = _M_pReservedSource->consume(_SavedId, this);
11235 
11236  runtime_object_identity _OldId = NULL;
11237  _OldId = _InterlockedExchange((volatile long *) &_M_reservedId, -1);
11238 
11239  _CONCRT_ASSERT(_OldId == _SavedId);
11240 
11241  // Release the reference on the source
11243  this->_M_connectedSources.release();
11244  }
11245  }
11246 
11250 
11252  {
11253  bool retVal = false;
11254 
11255  if (_M_pReservedSource != NULL)
11256  {
11257  runtime_object_identity _SavedId = _M_reservedId;
11258  // If the _M_savedId is still -1, then swap the succeeded one back
11259  _M_pReservedSource->release(_SavedId, this);
11260 
11261  if (_InterlockedCompareExchange((volatile long *) &_M_savedId, _SavedId, -1) == -1)
11262  {
11263  retVal = true;
11264  }
11265 
11266  // Release the reference on the source
11268  this->_M_connectedSources.release();
11269  }
11270 
11271  return retVal;
11272  }
11273 
11274 protected:
11275 
11276  //
11277  // propagator_block protected function implementation
11278  //
11279 
11299 
11301  {
11302  // Change the message ID. If it was -1, that means an async-send needs to occur
11303  if (_InterlockedExchange((volatile long *) &_M_savedId, _PMessage->msg_id()) == -1)
11304  {
11305  this->async_send(NULL);
11306  }
11307 
11308  // Always return postponed. This message will be consumed
11309  // in the LWT
11310 
11311  return postponed;
11312  }
11313 
11323 
11324  virtual message<size_t> * accept_message(runtime_object_identity _MsgId)
11325  {
11326  // This check is to prevent spoofing and verify that the propagated message is
11327  // the one that is accepted at the end.
11328  if (this->_M_pSendMessage == NULL || _MsgId != this->_M_pSendMessage->msg_id())
11329  {
11330  return NULL;
11331  }
11332 
11333  //
11334  // Instead of returning the internal message, we return a copy of the
11335  // message passed in.
11336  //
11337  // Because we are returning a copy, the accept routine for a _Non_greedy_node
11338  // does not need to grab the internal lock.
11339  //
11340  return (new message<size_t>(this->_M_pSendMessage->payload));
11341  }
11342 
11352 
11354  {
11355  _R_lock _Lock(_M_resetLock);
11356 
11357  if (this->_M_pSendMessage == NULL)
11358  {
11359  this->_Create_send_message();
11360  }
11361 
11362  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
11363  {
11364  ITarget<size_t> * _PTarget = *_Iter;
11365  _PTarget->propagate(this->_M_pSendMessage, this);
11366  }
11367  }
11368 
11369 private:
11370 
11371  //
11372  // Private Data Members
11373  //
11374 
11375  // The source where we have reserved a message
11377 
11378  // The lock used to protect modification during a reset
11380 
11381  // For non-greedy order nodes, the message ID of the message to reserve/consume
11382  runtime_object_identity _M_savedId;
11383 
11384  // For non-greedy order nodes, the reserved ID of the message that was reserved
11385  runtime_object_identity _M_reservedId;
11386 
11387  // The marker that indicates that _Non_greedy_node has reserved a message
11388  volatile bool _M_fIsInitialized;
11389 
11390 private:
11391  //
11392  // Hide assignment operator and copy constructor
11393  //
11394  _Non_greedy_node const & operator=(_Non_greedy_node const &); // no assignment operator
11395  _Non_greedy_node(_Non_greedy_node const &); // no copy constructor
11396 };
11397 
11398 //**************************************************************************
11399 // Choice:
11400 //**************************************************************************
11401 
11418 
11419 template<class _Type>
11420 class choice: public ISource<size_t>
11421 {
11422 public:
11423 
11443 
11444  explicit choice(_Type _Tuple) : _M_sourceTuple(_Tuple), _M_pScheduler(NULL), _M_pScheduleGroup(NULL)
11445  {
11447  _Initialize_choices<0>();
11448  }
11449 
11450 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
11451 
11474  choice(Scheduler& _PScheduler, _Type _Tuple) : _M_sourceTuple(_Tuple), _M_pScheduler(&_PScheduler), _M_pScheduleGroup(NULL)
11475  {
11477  _Initialize_choices<0>();
11478  }
11479 
11503 
11504  choice(ScheduleGroup& _PScheduleGroup, _Type _Tuple) : _M_sourceTuple(_Tuple), _M_pScheduler(NULL), _M_pScheduleGroup(&_PScheduleGroup)
11505  {
11506  _M_pSingleAssignment = new single_assignment<size_t>(_PScheduleGroup);
11507  _Initialize_choices<0>();
11508  }
11509 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
11510 
11531 
11532  choice(choice && _Choice)
11533  {
11534  // Copy scheduler group or scheduler to the new object.
11535  _M_pScheduleGroup = _Choice._M_pScheduleGroup;
11536  _M_pScheduler = _Choice._M_pScheduler;
11537 
11538  // Single assignment is heap allocated, so simply copy the pointer. If it already has
11539  // a value, it will be preserved.
11540  _M_pSingleAssignment = _Choice._M_pSingleAssignment;
11541  _Choice._M_pSingleAssignment = NULL;
11542 
11543  // Invoke copy assignment for tuple to copy pointers to message blocks.
11544  _M_sourceTuple = _Choice._M_sourceTuple;
11545 
11546  // Copy the pointers to order nodes to a new object and zero out in the old object.
11547  memcpy(_M_pSourceChoices, _Choice._M_pSourceChoices, sizeof(_M_pSourceChoices));
11548  memset(_Choice._M_pSourceChoices, 0, sizeof(_M_pSourceChoices));
11549  }
11550 
11554 
11556  {
11557  delete _M_pSingleAssignment;
11558  _Delete_choices<0>();
11559  }
11560 
11564 
11565  typedef typename _Type type;
11566 
11573 
11574  bool has_value() const
11575  {
11576  return _M_pSingleAssignment->has_value();
11577  }
11578 
11589 
11590  size_t index()
11591  {
11592  return _M_pSingleAssignment->value();
11593  }
11594 
11609 
11610  template <typename _Payload_type>
11611  _Payload_type const & value()
11612  {
11614  }
11615 
11616  //
11617  // ISource public function implementations
11618  //
11619 
11626 
11627  virtual void link_target(_Inout_ ITarget<size_t> * _PTarget)
11628  {
11629  _M_pSingleAssignment->link_target(_PTarget);
11630  }
11631 
11638 
11639  virtual void unlink_target(_Inout_ ITarget<size_t> * _PTarget)
11640  {
11642  }
11643 
11651 
11652  virtual void unlink_targets()
11653  {
11655  }
11656 
11669 
11670  virtual message<size_t> * accept(runtime_object_identity _MsgId, _Inout_ ITarget<size_t> * _PTarget)
11671  {
11672  return _M_pSingleAssignment->accept(_MsgId, _PTarget);
11673  }
11674 
11693 
11694  virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget<size_t> * _PTarget)
11695  {
11696  return _M_pSingleAssignment->reserve(_MsgId, _PTarget);
11697  }
11698 
11716 
11717  virtual message<size_t> * consume(runtime_object_identity _MsgId, _Inout_ ITarget<size_t> * _PTarget)
11718  {
11719  return _M_pSingleAssignment->consume(_MsgId, _PTarget);
11720  }
11721 
11731 
11732  virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget<size_t> * _PTarget)
11733  {
11734  _M_pSingleAssignment->release(_MsgId, _PTarget);
11735  }
11736 
11747 
11748  virtual void acquire_ref(_Inout_ ITarget<size_t> * _PTarget)
11749  {
11750  _M_pSingleAssignment->acquire_ref(_PTarget);
11751  }
11752 
11763 
11764  virtual void release_ref(_Inout_ ITarget<size_t> * _PTarget)
11765  {
11766  _M_pSingleAssignment->release_ref(_PTarget);
11767  }
11768 
11769 private:
11770  template<int _Index>
11772 
11777 
11778  template<int _Index>
11780  {
11781  std::tuple_element_t<_Index, _Type> _Item = std::get<_Index>(_M_sourceTuple);
11782  _Reserving_node_source_type<_Index> * _Order_node_element = NULL;
11783 
11784  if (_M_pScheduleGroup != NULL)
11785  {
11786  _Order_node_element = new _Reserving_node_source_type<_Index>(*_M_pScheduleGroup, _Item, _Index);
11787  }
11788  else if (_M_pScheduler != NULL)
11789  {
11790  _Order_node_element = new _Reserving_node_source_type<_Index>(*_M_pScheduler, _Item, _Index);
11791  }
11792  else
11793  {
11794  _Order_node_element = new _Reserving_node_source_type<_Index>(_Item, _Index);
11795  }
11796 
11797  _M_pSourceChoices[_Index] = _Order_node_element;
11798  _Order_node_element->link_target(_M_pSingleAssignment);
11799  _Initialize_choices<_Index + 1>();
11800  }
11801 
11806 
11807  template<> void _Initialize_choices<std::tuple_size<_Type>::value>()
11808  {
11809  }
11810 
11815 
11816  template<int _Index>
11818  {
11819  delete static_cast<_Reserving_node_source_type<_Index> *>(_M_pSourceChoices[_Index]);
11820  _M_pSourceChoices[_Index] = NULL;
11821  _Delete_choices<_Index + 1>();
11822  }
11823 
11828 
11829  template<> void _Delete_choices<std::tuple_size<_Type>::value>()
11830  {
11831  }
11832 
11833  // Array of pointers to _Reserving_node elements representing each source
11834  void * _M_pSourceChoices[std::tuple_size<_Type>::value];
11835 
11836  // Single assignment which chooses between source messaging blocks
11838 
11839  // Tuple of messaging blocks that are sources to this choice
11841 
11842  // The scheduler to propagate messages on
11843  Scheduler * _M_pScheduler;
11844 
11845  // The schedule group to propagate messages on
11846  ScheduleGroup * _M_pScheduleGroup;
11847 
11848 private:
11849  //
11850  // Hide assignment operator
11851  //
11852  choice const &operator =(choice const &); // no assignment operator
11853  choice(choice const &); // no copy constructor
11854 };
11855 
11856 // Templated factory functions that create a choice, three flavors
11857 
11858 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
11859 
11890 template<typename _Type1, typename _Type2, typename... _Types>
11891 choice<std::tuple<_Type1, _Type2, _Types...>>
11892 make_choice(Scheduler& _PScheduler, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
11893 {
11894  return choice<std::tuple<_Type1, _Type2, _Types...>>(_PScheduler, std::make_tuple(_Item1, _Item2, _Items...));
11895 }
11896 
11928 
11929 template<typename _Type1, typename _Type2, typename... _Types>
11930 choice<std::tuple<_Type1, _Type2, _Types...>>
11931 make_choice(ScheduleGroup& _PScheduleGroup, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
11932 {
11933  return choice<std::tuple<_Type1, _Type2, _Types...>>(_PScheduleGroup, std::make_tuple(_Item1, _Item2, _Items...));
11934 }
11935 
11936 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
11937 
11964 
11965 template<typename _Type1, typename _Type2, typename... _Types>
11966 choice<std::tuple<_Type1, _Type2, _Types...>>
11967 make_choice(_Type1 _Item1, _Type2 _Item2, _Types... _Items)
11968 {
11969  return choice<std::tuple<_Type1, _Type2, _Types...>>(std::make_tuple(_Item1, _Item2, _Items...));
11970 }
11971 
11972 //**************************************************************************
11973 // Join:
11974 //**************************************************************************
11975 
11976 // Template specialization used to unwrap the types from within a tuple.
11977 
11978 
11979 template <typename _Tuple> struct _Unwrap;
11980 
11987 
11988 template <typename... _Types>
11989 struct _Unwrap<std::tuple<_Types...>>
11990 {
11991  typedef std::tuple<typename std::remove_pointer_t<_Types>::source_type...> type;
11992 };
11993 
12004 
12005 template<typename _Type, typename _Destination_type, join_type _Jtype>
12006 class _Join_node: public propagator_block<single_link_registry<ITarget<_Destination_type>>, multi_link_registry<ISource<size_t>>>
12007 {
12008 private:
12011 
12012 public:
12016 
12021 
12022  _Join_node() : _M_counter(std::tuple_size<_Destination_type>::value)
12023  {
12025  }
12026 
12034 
12035  _Join_node(Scheduler& _PScheduler) : _M_counter(std::tuple_size<_Destination_type>::value)
12036  {
12037  this->initialize_source_and_target(&_PScheduler);
12038  }
12039 
12047 
12048  _Join_node(ScheduleGroup& _PScheduleGroup) : _M_counter(std::tuple_size<_Destination_type>::value)
12049  {
12050  this->initialize_source_and_target(NULL, &_PScheduleGroup);
12051  }
12052 
12056 
12058  {
12059  // Remove all links
12060  this->remove_network_links();
12061 
12062  // Clean up any messages left in this message block
12064  }
12065 
12066 protected:
12067 
12082 
12084  {
12085  // This join block is connected to the _Order_node sources, which know not to send
12086  // any more messages until join propagates them further. That is why join can
12087  // always accept the incoming messages.
12088 
12089  _PMessage = _PSource->accept(_PMessage->msg_id(), this);
12090 
12091  //
12092  // Source block created an int message only to notify join that the real
12093  // payload is available. There is no need to keep this message around.
12094  //
12095  _CONCRT_ASSERT(_PMessage != NULL);
12096  delete _PMessage;
12097 
12098  long _Ret_val = _InterlockedDecrement(&_M_counter);
12099 
12100  _CONCRT_ASSERT(_Ret_val >= 0);
12101 
12102  if (_Ret_val == 0)
12103  {
12104  //
12105  // All source messages are now received so join can propagate them further
12106  //
12107  this->async_send(NULL);
12108  }
12109 
12110  return accepted;
12111  }
12112 
12122 
12123  virtual message<_Destination_type> * accept_message(runtime_object_identity _MsgId)
12124  {
12125  //
12126  // Peek at the head message in the message buffer. If the IDs match
12127  // dequeue and transfer ownership
12128  //
12130 
12131  if (_M_messageBuffer._Is_head(_MsgId))
12132  {
12133  _Msg = _M_messageBuffer._Dequeue();
12134  }
12135 
12136  return _Msg;
12137  }
12138 
12152 
12153  virtual bool reserve_message(runtime_object_identity _MsgId)
12154  {
12155  // Allow reservation if this is the head message
12156  return _M_messageBuffer._Is_head(_MsgId);
12157  }
12158 
12172 
12173  virtual message<_Destination_type> * consume_message(runtime_object_identity _MsgId)
12174  {
12175  // By default, accept the message
12176  return accept_message(_MsgId);
12177  }
12178 
12185 
12186  virtual void release_message(runtime_object_identity _MsgId)
12187  {
12188  // The head message is the one reserved.
12189  if (!_M_messageBuffer._Is_head(_MsgId))
12190  {
12191  throw message_not_found();
12192  }
12193  }
12194 
12198 
12199  virtual void resume_propagation()
12200  {
12201  // If there are any messages in the buffer, propagate them out
12202  if (_M_messageBuffer._Count() > 0)
12203  {
12204  this->async_send(NULL);
12205  }
12206  }
12207 
12214 
12216  {
12217  // There is only a single target.
12219  }
12220 
12230 
12232  {
12234 
12235  if (_M_counter == 0)
12236  {
12237  bool fIsNonGreedy = (_Jtype == non_greedy);
12238 
12239  if (fIsNonGreedy)
12240  {
12242  {
12243  return;
12244  }
12245  }
12246 
12247  if (!fIsNonGreedy)
12248  {
12249  // Because a greedy join has captured all input, we can reset
12250  // the counter to the total number of inputs
12251  _InterlockedExchange(&_M_counter, std::tuple_size<_Destination_type>::value);
12252  }
12253 
12254  _Msg = _Create_send_message();
12255  }
12256 
12257  if (_Msg != NULL)
12258  {
12259  _M_messageBuffer._Enqueue(_Msg);
12260 
12261  if (!_M_messageBuffer._Is_head(_Msg->msg_id()))
12262  {
12263  // another message is at the head of the outbound message queue and blocked
12264  // simply return
12265  return;
12266  }
12267  }
12268 
12270  }
12271 
12272 private:
12273 
12283 
12284  template<int _Index>
12285  bool _Try_consume_source_messages(_Destination_type & _Destination_tuple, ISource<size_t> ** _Sources)
12286  {
12288  _Non_greedy_node_source_type * _Node = static_cast<_Non_greedy_node_source_type *>(_Sources[_Index]);
12289 
12290  // Increment the counter once for each reservation
12292 
12293  if (_Node->_Reserve_received_message())
12294  {
12295  bool _Ret_val = _Try_consume_source_messages<_Index + 1>(_Destination_tuple, _Sources);
12296 
12297  if (_Ret_val)
12298  {
12299  _Node->_Consume_received_message();
12300  }
12301  else
12302  {
12303  if (_Node->_Release_received_message())
12304  {
12305  // If _Release_received_message() restored the ID, decrement the count for that
12306  // restoration
12307  if (_InterlockedDecrement(&_M_counter) == 0)
12308  {
12309  this->async_send(NULL);
12310  }
12311  }
12312  }
12313 
12314  return _Ret_val;
12315  }
12316 
12317  return false;
12318  }
12319 
12327 
12328  template<> bool _Try_consume_source_messages<std::tuple_size<_Type>::value>(_Destination_type &, ISource<size_t> **)
12329  {
12330  return true;
12331  }
12332 
12341 
12343  {
12344  _Destination_type _Destination_tuple;
12345 
12346  // Populate the sources buffer
12347  ISource<size_t> * _Sources[std::tuple_size<_Type>::value];
12348  size_t _Index = 0;
12349 
12350  // Get an iterator which will keep a reference on the connected sources
12351  source_iterator _Iter = this->_M_connectedSources.begin();
12352 
12353  while (*_Iter != NULL)
12354  {
12355  ISource<size_t> * _PSource = *_Iter;
12356 
12357  if (_PSource == NULL)
12358  {
12359  // One of the sources disconnected
12360  break;
12361  }
12362 
12363  if (_Index >= std::tuple_size<_Type>::value)
12364  {
12365  // More sources that we expect
12366  break;
12367  }
12368 
12369  _Sources[_Index] = _PSource;
12370  _Index++;
12371  ++_Iter;
12372  }
12373 
12374  // The order nodes should not have unlinked while the join node is
12375  // active.
12376 
12377  if (_Index != std::tuple_size<_Type>::value)
12378  {
12379  // On debug build assert to help debugging
12380  _CONCRT_ASSERT(_Index == std::tuple_size<_Type>::value);
12381  return false;
12382  }
12383 
12384  bool _IsAcquireSuccessful = _Try_consume_source_messages<0>(_Destination_tuple, _Sources);
12385 
12386  return _IsAcquireSuccessful;
12387  }
12388 
12395 
12397  {
12398  message<_Target_type> * _Msg = _MessageBuffer._Peek();
12399 
12400  // If someone has reserved the _Head message, don't propagate anymore
12401  if (this->_M_pReservedFor != NULL)
12402  {
12403  return;
12404  }
12405 
12406  while (_Msg != NULL)
12407  {
12408  message_status _Status = declined;
12409 
12410  // Always start from the first target that linked
12411  for (target_iterator _Iter = this->_M_connectedTargets.begin(); *_Iter != NULL; ++_Iter)
12412  {
12413  ITarget<_Target_type> * _PTarget = *_Iter;
12414  _Status = _PTarget->propagate(_Msg, this);
12415 
12416  // Ownership of message changed. Do not propagate this
12417  // message to any other target.
12418  if (_Status == accepted)
12419  {
12420  break;
12421  }
12422 
12423  // If the target just propagated to reserved this message, stop
12424  // propagating it to others
12425  if (this->_M_pReservedFor != NULL)
12426  {
12427  break;
12428  }
12429  }
12430 
12431  // If status is anything other than accepted, then the head message
12432  // was not propagated out. Thus, nothing after it in the queue can
12433  // be propagated out. Cease propagation.
12434  if (_Status != accepted)
12435  {
12436  break;
12437  }
12438 
12439  // Get the next message
12440  _Msg = _MessageBuffer._Peek();
12441  }
12442  }
12443 
12448 
12450  {
12451  _Destination_type _Destination_tuple;
12452 
12453  // Populate the sources buffer
12454  ISource<size_t> * _Sources[std::tuple_size<_Type>::value];
12455  size_t _Index = 0;
12456 
12457  // Get an iterator which will keep a reference on the connected sources
12458  source_iterator _Iter = this->_M_connectedSources.begin();
12459 
12460  while (*_Iter != NULL)
12461  {
12462  ISource<size_t> * _PSource = *_Iter;
12463 
12464  if (_PSource == NULL)
12465  {
12466  // One of the sources disconnected
12467  break;
12468  }
12469 
12470  // Avoid buffer overrun
12471  if (_Index >= std::tuple_size<_Type>::value)
12472  {
12473  // More sources that we expect
12474  break;
12475  }
12476 
12477  _Sources[_Index] = *_Iter;
12478  _Index++;
12479  ++_Iter;
12480  }
12481 
12482  // The order nodes should not have unlinked while the join node is
12483  // active.
12484  if (_Index != std::tuple_size<_Type>::value)
12485  {
12486  // On debug build assert to help debugging
12487  _CONCRT_ASSERT(_Index == std::tuple_size<_Type>::value);
12488  return NULL;
12489  }
12490 
12491  _Populate_destination_tuple<0>(_Destination_tuple, _Sources);
12492 
12493  return new message<_Destination_type>(_Destination_tuple);
12494  }
12495 
12500 
12502  {
12503  // Delete any messages remaining in the output queue
12504  for (;;)
12505  {
12506  message<_Destination_type> * _Msg = _M_messageBuffer._Dequeue();
12507  if (_Msg == NULL)
12508  {
12509  break;
12510  }
12511  delete _Msg;
12512  }
12513  }
12514 
12518 
12519  template<int _Index>
12520  void _Populate_destination_tuple(_Destination_type & _Destination_tuple, ISource<size_t> ** _Sources)
12521  {
12523  _Order_node_base_source_type * _Node = static_cast<_Order_node_base_source_type *>(_Sources[_Index]);
12524 
12525  std::get<_Index>(_Destination_tuple) = _Node->value();
12526  _Node->_Reset();
12527 
12528  _Populate_destination_tuple<_Index + 1>(_Destination_tuple, _Sources);
12529  }
12530 
12535 
12536  template<> void _Populate_destination_tuple<std::tuple_size<_Type>::value>(_Destination_type &, ISource<size_t> **)
12537  {
12538  }
12539 
12540  // A tuple containing a collection of source messaging blocks
12542 
12543  // Counts messages received by sources of this node and is used to trigger propagation to targets
12544  // This value starts at the total number of inputs and counts down to zero. When it reaches zero,
12545  // a join of the inputs is started.
12546  volatile long _M_counter;
12547 
12548  // Buffer to hold outgoing messages
12550 
12551 private:
12552  //
12553  // Hide assignment operator and copy constructor
12554  //
12555  _Join_node(const _Join_node & _Join); // no copy constructor
12556  _Join_node const &operator =(_Join_node const &); // no assignment operator
12557 };
12558 
12579 
12580 template<typename _Type, join_type _Jtype = non_greedy>
12581 class multitype_join: public ISource<typename _Unwrap<_Type>::type>
12582 {
12583 public:
12584 
12586 
12606 
12608  {
12610  _Initialize_joins<0>();
12611  }
12612 
12613 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
12614 
12637  multitype_join(Scheduler& _PScheduler, _Type _Tuple) : _M_sourceTuple(_Tuple), _M_pScheduler(&_PScheduler), _M_pScheduleGroup(NULL)
12638  {
12640  _Initialize_joins<0>();
12641  }
12642 
12666 
12667  multitype_join(ScheduleGroup& _PScheduleGroup, _Type _Tuple) : _M_sourceTuple(_Tuple), _M_pScheduler(NULL), _M_pScheduleGroup(&_PScheduleGroup)
12668  {
12669  _M_pJoinNode = new _Join_node<_Type, _Destination_type, _Jtype>(_PScheduleGroup);
12670  _Initialize_joins<0>();
12671  }
12672 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
12673 
12694 
12696  {
12697  // Copy scheduler group or scheduler to the new object.
12698  _M_pScheduleGroup = _Join._M_pScheduleGroup;
12699  _M_pScheduler = _Join._M_pScheduler;
12700 
12701  // Single assignment is heap allocated, so simply copy the pointer. If it already has
12702  // a value, it will be preserved.
12703  _M_pJoinNode = _Join._M_pJoinNode;
12704  _Join._M_pJoinNode = NULL;
12705 
12706  // Invoke copy assignment for tuple to copy pointers to message blocks.
12707  _M_sourceTuple = _Join._M_sourceTuple;
12708 
12709  // Copy the pointers to order nodes to a new object and zero out in the old object.
12710  memcpy(_M_pSourceJoins, _Join._M_pSourceJoins, sizeof(_M_pSourceJoins));
12711  memset(_Join._M_pSourceJoins, 0, sizeof(_M_pSourceJoins));
12712  }
12713 
12717 
12719  {
12720  delete _M_pJoinNode;
12721  _Delete_joins<0>();
12722  }
12723 
12727 
12728  typedef typename _Type type;
12729 
12730  //
12731  // ISource public function implementations
12732  //
12733 
12740 
12742  {
12743  _M_pJoinNode->link_target(_PTarget);
12744  }
12745 
12752 
12754  {
12755  _M_pJoinNode->unlink_target(_PTarget);
12756  }
12757 
12761 
12762  virtual void unlink_targets()
12763  {
12764  _M_pJoinNode->unlink_targets();
12765  }
12766 
12779 
12780  virtual message<_Destination_type> * accept(runtime_object_identity _MsgId, _Inout_ ITarget<_Destination_type> * _PTarget)
12781  {
12782  return _M_pJoinNode->accept(_MsgId, _PTarget);
12783  }
12784 
12803 
12804  virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget<_Destination_type> * _PTarget)
12805  {
12806  return _M_pJoinNode->reserve(_MsgId, _PTarget);
12807  }
12808 
12826 
12827  virtual message<_Destination_type> * consume(runtime_object_identity _MsgId, _Inout_ ITarget<_Destination_type> * _PTarget)
12828  {
12829  return _M_pJoinNode->consume(_MsgId, _PTarget);
12830  }
12831 
12841 
12842  virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget<_Destination_type> * _PTarget)
12843  {
12844  _M_pJoinNode->release(_MsgId, _PTarget);
12845  }
12846 
12857 
12859  {
12860  _M_pJoinNode->acquire_ref(_PTarget);
12861  }
12862 
12873 
12875  {
12876  _M_pJoinNode->release_ref(_PTarget);
12877  }
12878 
12879 private:
12880  template<int _Index>
12881  using _Source_type = typename std::remove_pointer_t<std::tuple_element_t<_Index, _Type>>::source_type;
12882 
12883  template<int _Index>
12885 
12892 
12893  template<int _Index>
12895  {
12896  std::tuple_element_t<_Index, _Type> _Item = std::get<_Index>(_M_sourceTuple);
12897  _Order_node_base_source_type<_Index> * _Order_node_element = NULL;
12898 
12899  if (_Jtype == non_greedy)
12900  {
12901  typedef _Non_greedy_node<_Source_type<_Index>> _Non_greedy_node_source_type;
12902 
12903  if (_M_pScheduleGroup != NULL)
12904  {
12905  _Order_node_element = new _Non_greedy_node_source_type(*_M_pScheduleGroup, _Item, _Index);
12906  }
12907  else if (_M_pScheduler != NULL)
12908  {
12909  _Order_node_element = new _Non_greedy_node_source_type(*_M_pScheduler, _Item, _Index);
12910  }
12911  else
12912  {
12913  _Order_node_element = new _Non_greedy_node_source_type(_Item, _Index);
12914  }
12915  }
12916  else
12917  {
12918  typedef _Greedy_node<_Source_type<_Index>> _Greedy_node_source_type;
12919 
12920  if (_M_pScheduleGroup != NULL)
12921  {
12922  _Order_node_element = new _Greedy_node_source_type(*_M_pScheduleGroup, _Item, _Index);
12923  }
12924  else if (_M_pScheduler != NULL)
12925  {
12926  _Order_node_element = new _Greedy_node_source_type(*_M_pScheduler, _Item, _Index);
12927  }
12928  else
12929  {
12930  _Order_node_element = new _Greedy_node_source_type(_Item, _Index);
12931  }
12932  }
12933  _M_pSourceJoins[_Index] = _Order_node_element;
12934  _Order_node_element->link_target(_M_pJoinNode);
12935  _Initialize_joins<_Index + 1>();
12936  }
12937 
12942 
12943  template<> void _Initialize_joins<std::tuple_size<_Type>::value>()
12944  {
12945  }
12946 
12953 
12954  template<int _Index>
12956  {
12957  delete static_cast<_Order_node_base_source_type<_Index> *>(_M_pSourceJoins[_Index]);
12958  _M_pSourceJoins[_Index] = NULL;
12959  _Delete_joins<_Index + 1>();
12960  }
12961 
12966 
12967  template<> void _Delete_joins<std::tuple_size<_Type>::value>()
12968  {
12969  }
12970 
12971  // Array of pointers to _Order_node elements representing each source
12972  void * _M_pSourceJoins[std::tuple_size<_Type>::value];
12973 
12974  // Join node that collects source messaging block messages
12976 
12977  // Tuple of messaging blocks that are sources to this multitype_join
12979 
12980  // The scheduler to propagate messages on
12981  Scheduler * _M_pScheduler;
12982 
12983  // The schedule group to propagate messages on
12984  ScheduleGroup * _M_pScheduleGroup;
12985 
12986 private:
12987  //
12988  // Hide assignment operator
12989  //
12990  multitype_join const &operator =(multitype_join const &); // no assignment operator
12991  multitype_join(multitype_join const &); // no copy constructor
12992 };
12993 
12994 // Templated factory functions that create a join, three flavors
12995 
12996 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
12997 
13028 template<typename _Type1, typename _Type2, typename... _Types>
13029 multitype_join<std::tuple<_Type1, _Type2, _Types...>>
13030 make_join(Scheduler& _PScheduler, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
13031 {
13032  return multitype_join<std::tuple<_Type1, _Type2, _Types...>>(_PScheduler, std::make_tuple(_Item1, _Item2, _Items...));
13033 }
13034 
13066 
13067 template<typename _Type1, typename _Type2, typename... _Types>
13068 multitype_join<std::tuple<_Type1, _Type2, _Types...>>
13069 make_join(ScheduleGroup& _PScheduleGroup, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
13070 {
13071  return multitype_join<std::tuple<_Type1, _Type2, _Types...>>(_PScheduleGroup, std::make_tuple(_Item1, _Item2, _Items...));
13072 }
13073 
13074 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
13075 
13102 
13103 template<typename _Type1, typename _Type2, typename... _Types>
13104 multitype_join<std::tuple<_Type1, _Type2, _Types...>>
13105 make_join(_Type1 _Item1, _Type2 _Item2, _Types... _Items)
13106 {
13107  return multitype_join<std::tuple<_Type1, _Type2, _Types...>>(std::make_tuple(_Item1, _Item2, _Items...));
13108 }
13109 
13110 // Templated factory functions that create a *greedy* join, three flavors
13111 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
13112 
13144 template<typename _Type1, typename _Type2, typename... _Types>
13145 multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>
13146 make_greedy_join(Scheduler& _PScheduler, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
13147 {
13148  return multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>(_PScheduler, std::make_tuple(_Item1, _Item2, _Items...));
13149 }
13150 
13182 
13183 template<typename _Type1, typename _Type2, typename... _Types>
13184 multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>
13185 make_greedy_join(ScheduleGroup& _PScheduleGroup, _Type1 _Item1, _Type2 _Item2, _Types... _Items)
13186 {
13187  return multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>(_PScheduleGroup, std::make_tuple(_Item1, _Item2, _Items...));
13188 }
13189 
13190 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
13191 
13218 
13219 template<typename _Type1, typename _Type2, typename... _Types>
13220 multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>
13221 make_greedy_join(_Type1 _Item1, _Type2 _Item2, _Types... _Items)
13222 {
13223  return multitype_join<std::tuple<_Type1, _Type2, _Types...>, greedy>(std::make_tuple(_Item1, _Item2, _Items...));
13224 }
13225 
13226 //**************************************************************************
13227 // Agents:
13228 //**************************************************************************
13229 
13236 
13241 
13246 
13251 
13256 
13261 
13263 };
13264 
13272 
13273 class agent
13274 {
13275 public:
13285 
13286  _CONCRTIMP agent();
13287 
13288 #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP
13289 
13302  _CONCRTIMP agent(Scheduler& _PScheduler);
13303 
13317 
13318  _CONCRTIMP agent(ScheduleGroup& _PGroup);
13319 #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */
13320 
13329 
13330  _CONCRTIMP virtual ~agent();
13331 
13338 
13340 
13349 
13351 
13359 
13360  _CONCRTIMP bool start();
13361 
13370 
13371  _CONCRTIMP bool cancel();
13372 
13395 
13396  _CONCRTIMP static agent_status __cdecl wait(_Inout_ agent * _PAgent, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE);
13397 
13423 
13424  _CONCRTIMP static void __cdecl wait_for_all(size_t _Count, _In_reads_(_Count) agent ** _PAgents,
13425  _Out_writes_opt_(_Count) agent_status * _PStatus = NULL, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE);
13426 
13454 
13455  _CONCRTIMP static void __cdecl wait_for_one(size_t _Count, _In_reads_(_Count) agent ** _PAgents, agent_status& _Status,
13456  size_t& _Index, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE);
13457 
13458 protected:
13468 
13469  virtual void run() = 0;
13470 
13483 
13484  _CONCRTIMP bool done();
13485 
13489 
13491 
13492 private:
13493 
13494  // A flag to check of whether the agent can be started
13495  // This is initialized to TRUE and there is a race between Start() and Cancel() to set it
13496  // to FALSE. Once Started or Canceled, further calls to Start() or Cancel() will return false.
13497 
13498  volatile long _M_fStartable;
13499 
13500  // A flag to check of whether the agent can be canceled
13501  // This is initialized to TRUE and there is a race between Cancel() and the LWT executing
13502  // a task that has been started to set it to FALSE. If Cancel() wins, the task will not be
13503  // executed. If the LWT wins, Cancel() will return false.
13504 
13505  volatile long _M_fCancelable;
13506 
13507  // A static wrapper function that calls the Run() method. Used for scheduling of the task
13508 
13509  static void __cdecl _Agent_task_wrapper(void * data);
13510 
13511  Scheduler * _M_pScheduler;
13512  ScheduleGroup * _M_pScheduleGroup;
13513 
13514  //
13515  // Hide assignment operator and copy constructor
13516  //
13517  agent const &operator =(agent const&); // no assignment operator
13518  agent(agent const &); // no copy constructor
13519 };
13520 
13533 template <class _Type>
13534 void Trace_agents_register_name(_Inout_ _Type * _PObject, _In_z_ const wchar_t * _Name)
13535 {
13537 }
13538 
13539 } // namespace Concurrency
13540 
13541 namespace concurrency = ::Concurrency;
13542 
13543 #pragma warning(pop)
13544 #pragma pack(pop)
virtual message< size_t > * accept_message(runtime_object_identity _MsgId)
Accept the message by making a copy of the payload.
Definition: agents.h:11324
void decline_incoming_messages()
Indicates to the block that new messages should be declined.
Definition: agents.h:5856
_Message * _Peek()
Definition: agents.h:227
call(_Call_method const &_Func, filter_method const &_Filter)
Constructs a call messaging block.
Definition: agents.h:7168
virtual void unlink_source(_Inout_ ISource< _Source_type > *_PSource)
Unlinks a specified source block from this target_block object.
Definition: agents.h:4660
single_link_registry< ITarget< _Output > > _TargetLinkRegistry
Definition: agents.h:7483
volatile bool _M_fIsInitialized
Definition: agents.h:9100
multitype_join const & operator=(multitype_join const &)
volatile long _M_lwtCount
A counter to indicate the number of outstanding LWTs
Definition: agents.h:2416
void _Propagate_priority_order(::Concurrency::details::_Queue< message< _Target_type >> &_MessageBuffer)
Propagate messages in priority order.
Definition: agents.h:9688
void _Delete_choices()
Deletes all _Reserving_node elements that were created in _Initialize_choices.
Definition: agents.h:11817
virtual ~_AsyncOriginator()
Definition: agents.h:3981
single_assignment()
Constructs a single_assignment messaging block.
Definition: agents.h:8611
virtual bool supports_anonymous_source()
Overrides the supports_anonymous_source method to indicate that this block can accept messages offere...
Definition: agents.h:6200
void _Swap(_Myt &_Right)
Definition: agents.h:362
volatile long _M_referenceCount
Definition: agents.h:5548
_MessageProcessorType _M_messageProcessor
Processor used for asynchronous message handling
Definition: agents.h:5490
virtual message< _Target_type > * consume(runtime_object_identity _MsgId, _Inout_ ITarget< _Target_type > *_PTarget)
Consumes a message previously offered by this source_block object and successfully reserved by the ta...
Definition: agents.h:5108
void stop()
Stops the timer messaging block.
Definition: agents.h:8290
virtual void unlink_sources()
Unlinks all source blocks from this target_block object.
Definition: agents.h:4673
~single_assignment()
Destroys the single_assignment messaging block.
Definition: agents.h:8744
ISource< _Type > * _M_pReservedSource
Definition: agents.h:10554
::Concurrency::details::_Queue< message< _Output > > _M_messageBuffer
Message queue used to store outbound messages
Definition: agents.h:8083
~multitype_join()
Destroys the multitype_join messaging block.
Definition: agents.h:12718
virtual ~ISource()
Destroys the ISource object.
Definition: agents.h:2605
multitype_join(multitype_join &&_Join)
Constructs a multitype_join messaging block.
Definition: agents.h:12695
void _Invoke_handler(message< _Type > *_Msg)
Definition: agents.h:2350
_TargetLinkRegistry::iterator target_iterator
The iterator to walk the connected targets.
Definition: agents.h:4893
size_t _M_index
Definition: agents.h:422
_Reserving_node const & operator=(_Reserving_node const &)
virtual message_status propagate_message(_Inout_ message< _Source_type > *_PMessage, _Inout_ ISource< _Source_type > *_PSource)=0
When overridden in a derived class, this method asynchronously passes a message from an ISource block...
virtual message< size_t > * consume(runtime_object_identity _MsgId, _Inout_ ITarget< size_t > *_PTarget)
Consumes a message previously offered by this choice messaging block and successfully reserved by the...
Definition: agents.h:11717
virtual void propagate_to_any_targets(_Inout_opt_ message< _Output > *)
Executes the transformer function on the input messages.
Definition: agents.h:7952
volatile long _M_referenceCount
Definition: agents.h:3969
#define NULL
Definition: vcruntime.h:236
propagator_block()
Constructs a propagator_block object.
Definition: agents.h:5605
unbounded_buffer()
Constructs an unbounded_buffer messaging block.
Definition: agents.h:5941
static _CONCRTIMP void __cdecl _Yield()
This class describes an exception thrown when an invalid operation is performed that is not more accu...
Definition: pplinterface.h:132
void _Initialize(const _Type &_Value, _Inout_ ITarget< _Type > *_PTarget, bool _Repeating, _Inout_opt_ Scheduler *_PScheduler=NULL, _Inout_opt_ ScheduleGroup *_PScheduleGroup=NULL)
Common initialization.
Definition: agents.h:8510
virtual message< size_t > * accept(runtime_object_identity _MsgId, _Inout_ ITarget< size_t > *_PTarget)
Accepts a message that was offered by this choice block, transferring ownership to the caller...
Definition: agents.h:11670
reference operator[](size_t _Pos)
Definition: agents.h:336
Definition: agents.h:255
virtual message< _Type > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the single_assignment and reserved by the target...
Definition: agents.h:8992
void _Initialize_order_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, Scheduler *_PScheduler=NULL, ScheduleGroup *_PScheduleGroup=NULL)
Validate constructor arguments and fully connect this _Order_node_base.
Definition: agents.h:10139
void _Propagate_message()
Definition: agents.h:5519
ScheduleGroup * _M_pScheduleGroup
Definition: agents.h:11846
_Non_greedy_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Non_greedy_node within the specified scheduler, and places it on any schedule group of ...
Definition: agents.h:11081
ISource< _Type > * _M_pReservedSource
Definition: agents.h:11376
_Message ** _M_ppTail
Definition: agents.h:113
constexpr tuple< typename _Unrefwrap< _Types >::type...> make_tuple(_Types &&..._Args)
Definition: tuple:965
_Reserving_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Reserving_node within the specified scheduler, and places it on any schedule group of t...
Definition: agents.h:10271
virtual void process_input_messages(_Inout_ message< _Target_type > *_PMessage)
Process input messages. This is only useful for propagator blocks, which derive from source_block ...
Definition: agents.h:5340
choice(choice &&_Choice)
Constructs a choice messaging block.
Definition: agents.h:11532
~_MessageArray()
Definition: agents.h:9918
_MessageArray _M_messageArray
Definition: agents.h:9925
virtual void unlink_target(_Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, unlinks a target block from this ISource block, if found to be previously linked.
basic_ostream< _Elem, _Traits > & _Out(basic_ostream< _Elem, _Traits > &_Os, _Ty _Dx)
Definition: random:151
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this join messaging block.
Definition: agents.h:9500
virtual void _Reset()=0
Resets the _Order_node_base and prepares it for the next propagation
_Type _M_sourceTuple
Definition: agents.h:12541
Scheduler * _M_pScheduler
Definition: agents.h:11843
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:6946
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:5921
void _Process_message(message< _Target_type > *_PMessage)
Definition: agents.h:5510
agent const & operator=(agent const &)
void _Consume_received_message()
Called for a non_greedy type join block in order to consume the message in this join block that has b...
Definition: agents.h:11229
_CONCRTIMP agent_status status()
A synchronous source of status information from the agent.
virtual message_status send_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Synchronously passes a message from an ISource block to this single_assignment messaging block...
Definition: agents.h:8869
bool _Is_head(runtime_object_identity _MsgId)
Definition: agents.h:233
bool _Non_greedy_acquire_messages()
Tries to acquire all of the messages from the _Non_greedy_nodes. Each node has already indicated that...
Definition: agents.h:12342
virtual message< _Target_type > * consume_message(runtime_object_identity _MsgId)=0
When overridden in a derived class, consumes a message that was previously reserved.
void _Wait_for_completion()
Definition: agents.h:3927
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this overwrite_buffer messaging block.
Definition: agents.h:6878
event _M_ev
Definition: agents.h:3958
::Concurrency::runtime_object_identity _M_id
Definition: agents.h:101
static bool _send(ITarget< _Type > *_Trg, const _Type &_Data)
Definition: agents.h:4273
~_Non_greedy_node()
Cleans up any resources that may have been created by the _Order_node.
Definition: agents.h:11148
State _M_state
Definition: agents.h:8465
source_link_manager< _SourceLinkRegistry > _SourceLinkManager
The type of the source_link_manager this target_block object.
Definition: agents.h:4459
An event type that represents the linking of message blocks
Definition: concrt.h:5679
Definition: concrt.h:376
Non-greedy join messaging blocks postpone messages and try and consume them after all have arrived...
Definition: agents.h:9130
_Propagator_method _M_propagator
A message propagating object which exposes the callback to be invoked
Definition: agents.h:2434
virtual void propagate_to_any_targets(_Inout_opt_ message< size_t > *)
Takes the message and propagates it to all the targets of this _Order_node
Definition: agents.h:11353
join(size_t _NumInputs)
Constructs a join messaging block.
Definition: agents.h:9182
unsigned int _Count
Definition: xcomplex:668
An event type that represents the unlinking of message blocks
Definition: concrt.h:5685
virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget< _Destination_type > *_PTarget)
Releases a previous successful message reservation.
Definition: agents.h:12842
virtual void link_source(_Inout_ ISource< _Source_type > *_PSource)
Links a specified source block to this propagator_block object.
Definition: agents.h:5763
virtual void process_input_messages(_Inout_ message< _Source_type > *_PMessage)
Processes messages that are received as inputs.
Definition: agents.h:4826
static _CONCRTIMP void __cdecl _ScheduleTask(TaskProc _Proc, void *_Data)
virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, reserves a message previously offered by this ISource block...
virtual void sync_send(_Inout_opt_ message< _Target_type > *_Msg)
Synchronously queues up messages and starts a propagation task, if this has not been done already...
Definition: agents.h:5420
_SourceLinkRegistry::type::source_type _Source_type
The type of the payload for the incoming message to this propagator_block.
Definition: agents.h:5584
The basic message envelope containing the data payload being passed between messaging blocks...
Definition: agents.h:1776
Implements busy wait with no backoff
Definition: concrt.h:578
#define _CONCRT_ASSERT(x)
Definition: concrt.h:123
virtual message< _Type > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this overwrite_buffer messaging block, returning a copy of the ...
Definition: agents.h:6838
multitype_join< std::tuple< _Type1, _Type2, _Types...>, greedy > make_greedy_join(_Type1 _Item1, _Type2 _Item2, _Types..._Items)
Constructs a greedy multitype_join messaging block from an optional Scheduler or ScheduleGroup and tw...
Definition: agents.h:13221
virtual void unlink_target(_Inout_ ITarget< size_t > *_PTarget)
Unlinks a target block from this choice messaging block.
Definition: agents.h:11639
void async_send(_Inout_opt_ message< _Source_type > *_PMessage)
Asynchronously sends a message for processing.
Definition: agents.h:4775
runtime_object_identity _M_savedId
Definition: agents.h:10558
size_t _M_count
Definition: agents.h:116
_CONCRTIMP unsigned int _Release()
virtual ~target_block()
Destroys the target_block object.
Definition: agents.h:4484
void _Delete_joins()
Deletes all _Order_node elements that were created in _Initialize_joins.
Definition: agents.h:12955
virtual bool supports_anonymous_source()
Overrides the supports_anonymous_source method to indicate that this block can accept messages offere...
Definition: agents.h:7827
virtual message< _Type > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this single_assignment messaging block, returning a copy of the...
Definition: agents.h:8930
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:7120
~_Reserving_node()
Cleans up any resources that may have been created by the _Reserving_node.
Definition: agents.h:10366
Definition: agents.h:3687
void _Clear_queued_messages()
Definition: agents.h:2234
virtual void release_ref(_Inout_ ITarget< _Target_type > *_PTarget)
Releases a reference count on this source_block object.
Definition: agents.h:5208
virtual void process_incoming_message()=0
When overridden in a derived class, performs the forward processing of messages into the block...
bool asend(_Inout_ ITarget< _Type > *_Trg, const _Type &_Data)
An asynchronous send operation, which schedules a task to propagate the data to the target block...
Definition: agents.h:4394
The ITarget class is the interface for all target blocks. Target blocks consume messages offered to t...
Definition: agents.h:453
virtual message< _Output > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this transformer messaging block, transferring ownership to the...
Definition: agents.h:7843
void _Handle_message(message< _Target_type > *_PMessage)
Private methods.
Definition: agents.h:5500
::Concurrency::details::_Queue< message< _Destination_type > > _M_messageBuffer
Definition: agents.h:12549
The agent has been started, but not entered its run method.
Definition: agents.h:13247
virtual bool supports_anonymous_source()
Overrides the supports_anonymous_source method to indicate that this block can accept messages offere...
Definition: agents.h:6817
This class describes an exception thrown when a messaging block is given a pointer to a target which ...
Definition: concrt.h:1520
void(__cdecl * TaskProc)(void *)
Concurrency::details contains definitions of support routines in the public namespaces and one or mor...
Definition: concrt.h:251
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Link(const wchar_t *, const wchar_t *)
virtual message_status propagate_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this single_assignment messaging block...
Definition: agents.h:8805
void decline_incoming_messages()
Indicates to the block that new messages should be declined.
Definition: agents.h:4720
virtual message< _Type > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the timer and reserved by the target, transferring ownership...
Definition: agents.h:8392
_Type type
A type alias for _Type .
Definition: agents.h:1937
bool _internal_send(ITarget< _Type > *_PTarget, _Type const &_Value)
Definition: agents.h:3868
concurrent_queue< message< _Type > * > _M_queuedMessages
A queue of the messages
Definition: agents.h:2378
An event type that represents the creation of an object
Definition: concrt.h:5649
virtual void resume_propagation()=0
When overridden in a derived class, resumes propagation after a reservation has been released...
_Type source_type
A type alias for _Type .
Definition: agents.h:2737
__int64 _Trace_agents_get_id(_Type *_PObject)
Definition: agents.h:435
_Type type
A type alias for _Type .
Definition: agents.h:1902
virtual bool supports_anonymous_source()
When overridden in a derived class, returns true or false depending on whether the message block acce...
Definition: agents.h:2530
~join()
Destroys the join block.
Definition: agents.h:9336
virtual void link_target(_Inout_ ITarget< _Destination_type > *_PTarget)
Links a target block to this multitype_join messaging block.
Definition: agents.h:12741
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:8545
_Join_node const & operator=(_Join_node const &)
std::function< void(void)> _Propagator_method
The signature of the callback method invoked while propagating messages.
Definition: agents.h:2022
_Greedy_node const & operator=(_Greedy_node const &)
static _CONCRTIMP agent_status __cdecl wait(_Inout_ agent *_PAgent, unsigned int _Timeout=COOPERATIVE_TIMEOUT_INFINITE)
Waits for an agent to complete its task.
bool _M_fForceRepropagation
A bool to signal to the processor to force a repropagation to occur
Definition: agents.h:6496
Scheduler * _M_pScheduler
Definition: agents.h:13511
_TargetLinkRegistry _M_connectedTargets
Connected targets
Definition: agents.h:5484
~_Order_node_base()
Cleans up any resources that may have been created by the _Order_node.
Definition: agents.h:9997
void _Initialize_choices()
Constructs and initializes a _Reserving_node for each tuple messaging block passed in...
Definition: agents.h:11779
runtime_object_identity _M_savedId
Definition: agents.h:11382
The source_block class is an abstract base class for source-only blocks. The class provides basic lin...
Definition: agents.h:4879
volatile long _M_stopProcessing
A flag set in the destructor of a block to cease processing of new messages. This is required to guar...
Definition: agents.h:2410
virtual message< _Target_type > * accept(runtime_object_identity _MsgId, _Inout_ ITarget< _Target_type > *_PTarget)
Accepts a message that was offered by this source_block object, transferring ownership to the caller...
Definition: agents.h:5016
_TargetLinkRegistry::type::type _Target_type
The payload type of messages handled by this source_block.
Definition: agents.h:4887
_Dynamic_array()
Definition: agents.h:267
void _Done(message_status _Status)
Definition: agents.h:3945
virtual bool reserve(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3791
single_link_registry< ITarget< _Type > > _Target_registry
Definition: agents.h:3534
single_assignment(filter_method const &_Filter)
Constructs a single_assignment messaging block.
Definition: agents.h:8633
void _Push_back(_Type const &_Element)
Definition: agents.h:319
STL namespace.
message(_Type const &_P, runtime_object_identity _Id)
Constructs a message object.
Definition: agents.h:1810
_Type * _M_array
Definition: agents.h:419
virtual void release_message(runtime_object_identity _MsgId)=0
When overridden in a derived class, releases a previous message reservation.
The target did not accept the message.
Definition: agents.h:1751
message< _Type > * _M_pMessage
Definition: agents.h:7075
message(_Type const &_P)
Constructs a message object.
Definition: agents.h:1793
_Non_greedy_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Non_greedy_node within the specified scheduler, and places it on any schedule group of ...
Definition: agents.h:11053
Definition: agents.h:106
choice(_Type _Tuple)
Constructs a choice messaging block.
Definition: agents.h:11444
overwrite_buffer< agent_status > _M_status
Holds the current status of the agent.
Definition: agents.h:13490
virtual message< _Destination_type > * consume(runtime_object_identity _MsgId, _Inout_ ITarget< _Destination_type > *_PTarget)
Consumes a message previously offered by the multitype_join messaging block and successfully reserved...
Definition: agents.h:12827
virtual void unlink_source(_Inout_ ISource< _Source_type > *_PSource)
Unlinks a specified source block from this propagator_block object.
Definition: agents.h:5778
The target postponed the message.
Definition: agents.h:1756
The Concurrency namespace provides classes and functions that provide access to the Concurrency Runti...
Definition: agents.h:43
virtual message< _OutputType > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this join messaging block, transferring ownership to the caller...
Definition: agents.h:9470
virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget< size_t > *_PTarget)
Releases a previous successful message reservation.
Definition: agents.h:11732
void _Reset()
Resets the _Greedy_node and prepares it for the next propagation
Definition: agents.h:10767
bool _Reserve_received_message()
Called for a non_greedy type join block in order to reserve the message in this join block ...
Definition: agents.h:11187
Helper class used in multi-type greedy join blocks Ordered node is a single-target, single-source ordered propagator block
Definition: agents.h:10582
virtual void link_target(_Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, links a target block to this ISource block.
_FunctorType _Call_method
The function type that this block executes upon receiving a message.
Definition: agents.h:7118
virtual ~source_block()
Destroys the source_block object.
Definition: agents.h:4913
_CONCRTIMP void _Start()
::Concurrency::details::_ReentrantPPLLock _M_resetLock
Definition: agents.h:10951
virtual bool supports_anonymous_source()
Overrides the supports_anonymous_source method to indicate that this block can accept messages offere...
Definition: agents.h:7412
_SourceLinkManager::iterator source_iterator
The type of the iterator for the source_link_manager for this target_block object.
Definition: agents.h:4465
volatile long _M_counter
Definition: agents.h:12546
Helper class used in multi-type choice blocks Ordered node is a single-target, single-source ordered ...
Definition: agents.h:10194
join_type
The type of a join messaging block.
Definition: agents.h:9118
virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, releases a previous successful message reservation.
Scheduler * _M_pScheduler
Definition: agents.h:12981
virtual void release_ref(_Inout_ ITarget< size_t > *_PTarget)
Releases a reference count on this choice messaging block.
Definition: agents.h:11764
_Type _M_sourceTuple
Definition: agents.h:11840
void propagate_to_any_targets(_Inout_opt_ message< _OutputType > *)
Constructs an output message containing an input message from each source when they have all propagat...
Definition: agents.h:9580
Definition: agents.h:11979
virtual void link_source(_Inout_ ISource< _Source_type > *_PSource)
Links a specified source block to this target_block object.
Definition: agents.h:4642
The timer has been initialized, but not yet started.
Definition: agents.h:8127
virtual void acquire_ref(_Inout_ ITarget< _Destination_type > *_PTarget)
Acquires a reference count on this multitype_join messaging block, to prevent deletion.
Definition: agents.h:12858
An ordered_message_processor is a message_processor that allows message blocks to process messages in...
Definition: agents.h:2009
_Reserving_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Order_node within the specified schedule group. The scheduler is implied by the schedul...
Definition: agents.h:10353
#define _Out_writes_opt_(size)
Definition: sal.h:346
_Payload_type const & value()
Gets the message whose index was selected by the choice messaging block.
Definition: agents.h:11611
multitype_join< std::tuple< _Type1, _Type2, _Types...> > make_join(_Type1 _Item1, _Type2 _Item2, _Types..._Items)
Constructs a non_greedy multitype_join messaging block from an optional Scheduler or ScheduleGroup an...
Definition: agents.h:13105
void enable_batched_processing()
Enables batched processing for this block.
Definition: agents.h:4757
_Type _M_sourceTuple
Definition: agents.h:12978
virtual void unlink_source(_Inout_ ISource< _Type > *_PSource)=0
When overridden in a derived class, unlinks a specified source block from this ITarget block...
__int32 runtime_object_identity
Each message instance has an identity that follows it as it is cloned and passed between messaging co...
Definition: agents.h:51
Helper class used in multi-type non-greedy join blocks Ordered node is a single-target, single-source ordered propagator block
Definition: agents.h:10976
void _Invoke_link_source(ITarget< _Type > *_PLinkFrom)
Links this source to a target.
Definition: agents.h:2754
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:10198
void pause()
Stops the timer messaging block. If it is a repeating timer messaging block, it can be restarted with...
Definition: agents.h:8303
size_t _Size() const
Definition: agents.h:354
virtual void release(runtime_object_identity _MsgId, _Inout_ ITarget< _Target_type > *_PTarget)
Releases a previous successful message reservation.
Definition: agents.h:5157
virtual message< _Type > * accept(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3561
~_Join_node()
Cleans up any resources that may have been created by the join.
Definition: agents.h:12057
_Greedy_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Greedy_node within the specified scheduler, and places it on any schedule group of the ...
Definition: agents.h:10684
An event type that represents the name for an object
Definition: concrt.h:5691
message< _Type > * _M_pReceiveMessage
Definition: agents.h:10167
virtual void release_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, releases a reference count on this ISource block.
Definition: agents.h:3609
volatile bool _M_fIsInitialized
Definition: agents.h:11388
A timer messaging block is a single-target source_block capable of sending a message to its target af...
Definition: agents.h:8109
virtual message< _Type > * accept(runtime_object_identity _MsgId, _Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, accepts a message that was offered by this ISource block...
virtual message_status send_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Synchronously passes a message from an ISource block to this unbounded_buffer messaging block...
Definition: agents.h:6176
_CONCRTIMP void __cdecl _Trace_agents(Agents_EventType _Type, __int64 _AgentId,...)
size_t _M_size
Definition: agents.h:425
The agent finished without being canceled.
Definition: agents.h:13257
_Reserving_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Reserving_node within the default scheduler, and places it on any schedule group of the...
Definition: agents.h:10245
void _Wait_on_ref()
Definition: agents.h:3935
size_t index()
Returns an index into the tuple representing the element selected by the choice messaging block...
Definition: agents.h:11590
virtual void link_target_notification(_Inout_ ITarget< _Output > *)
A callback that notifies that a new target has been linked to this transformer messaging block...
Definition: agents.h:7936
_Type & reference
Definition: agents.h:261
virtual void process_input_messages(_Inout_ message< _Target_type > *_PMessage)
Process input messages. This is only useful for propagator blocks, which derive from source_block ...
Definition: agents.h:5808
size_t _Count() const
Definition: agents.h:132
message< std::vector< _Type > > *__cdecl _Create_new_message()
Constructs a new message from the data output.
Definition: agents.h:9743
bool send(ITarget< _Type > &_Trg, const _Type &_Data)
A synchronous send operation, which waits until the target either accepts or declines the message...
Definition: agents.h:4366
virtual message_status send_message(_Inout_ message< _Input > *_PMessage, _Inout_ ISource< _Input > *_PSource)
Synchronously passes a message from an ISource block to this transformer messaging block...
Definition: agents.h:7801
virtual bool reserve(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3585
bool has_value() const
Checks whether this single_assignment messaging block has been initialized with a value yet...
Definition: agents.h:8760
virtual message< _OutputType > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the join messaging block and reserved by the target...
Definition: agents.h:9520
choice< std::tuple< _Type1, _Type2, _Types...> > make_choice(_Type1 _Item1, _Type2 _Item2, _Types..._Items)
Constructs a choice messaging block from an optional Scheduler or ScheduleGroup and two or more input...
Definition: agents.h:11967
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:10980
The timer has started and been paused.
Definition: agents.h:8137
A multitype_join messaging block is a multi-source, single-target messaging block that combines toget...
Definition: agents.h:12581
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:9077
runtime_object_identity * _M_savedIds
Definition: agents.h:9936
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this single_assignment messaging block.
Definition: agents.h:8963
void _Populate_destination_tuple(_Destination_type &_Destination_tuple, ISource< size_t > **_Sources)
Copies payloads from all sources to destination tuple.
Definition: agents.h:12520
choice const & operator=(choice const &)
An unbounded_buffer messaging block is a multi-target, multi-source, ordered propagator_block capable...
Definition: agents.h:5917
void _Clear()
Definition: agents.h:307
bool _SpinOnce()
Spins for one time quantum,until a maximum spin is reached.
Definition: concrt.h:626
The message_processor class is the abstract base class for processing of message objects. There is no guarantee on the ordering of the messages.
Definition: agents.h:1930
bool _Release_received_message()
Called for a non_greedy type join block release a reservation on this block
Definition: agents.h:11251
overwrite_buffer const & operator=(overwrite_buffer const &)
unbounded_buffer(filter_method const &_Filter)
Constructs an unbounded_buffer messaging block.
Definition: agents.h:5964
multitype_join(_Type _Tuple)
Constructs a multitype_join messaging block.
Definition: agents.h:12607
_Queue()
Definition: agents.h:122
size_t _M_count
Definition: agents.h:9935
timer const & operator=(timer const &)
#define _InterlockedDecrementSizeT(_Target)
Definition: concrt.h:97
virtual ~ordered_message_processor()
Destroys the ordered_message_processor object.
Definition: agents.h:2057
std::tuple< typename std::remove_pointer_t< _Types >::source_type...> type
Definition: agents.h:11991
overwrite_buffer(filter_method const &_Filter)
Constructs an overwrite_buffer messaging block.
Definition: agents.h:6571
bool _internal_asend(ITarget< _Type > *_PTarget, _Type const &_Value)
Definition: agents.h:3643
virtual void resume_propagation()
Resumes propagation after a reservation has been released
Definition: agents.h:12199
virtual void link_target_notification(_Inout_ ITarget< std::vector< _Type >> *)
A callback that notifies that a new target has been linked to this join messaging block...
Definition: agents.h:9562
message< _Type > * _M_pMessage
Definition: agents.h:3679
virtual message< _Type > * accept(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3757
virtual message< _Type > * accept(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:4053
The timer has been started.
Definition: agents.h:8132
_Target_registry _M_connectedTargets
Definition: agents.h:4262
message< _Type > const & operator=(message< _Type > const &)
virtual void propagate_to_any_targets(_Inout_ message< _Type > *_PMessage)
Places the message _PMessage in this overwrite_buffer messaging block and offers it to all of the li...
Definition: agents.h:7001
static void __cdecl _Agent_task_wrapper(void *data)
volatile bool _M_fDeclineMessages
A bool that is set to indicate that all messages should be declined in preparation for deleting the b...
Definition: agents.h:5896
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by the source.
Definition: agents.h:12153
int i[4]
Definition: dvec.h:68
_Join_node(Scheduler &_PScheduler)
Constructs a join within the specified scheduler, and places it on any schedule group of the schedule...
Definition: agents.h:12035
::Concurrency::details::_NonReentrantPPLLock _M_asyncSendLock
A lock to use for queueing incoming messages.
Definition: agents.h:2384
single_link_registry< ITarget< size_t > > _TargetLinkRegistry
Definition: agents.h:10197
ScheduleGroup * _M_pScheduleGroup
Definition: agents.h:13512
virtual void link_source(_Inout_ ISource< _Type > *_PSource)=0
When overridden in a derived class, links a specified source block to this ITarget block...
virtual message_status send_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Synchronously passes a message from an ISource block to this call messaging block. It is invoked by the send method, when called by a source block.
Definition: agents.h:7380
_Type dequeue()
Removes an item from the unbounded_buffer messaging block.
Definition: agents.h:6111
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:6967
virtual void sync_send(_Inout_opt_ message< _Type > *_Msg)=0
When overridden in a derived class, places messages into the block synchronously. ...
virtual message_status propagate(_Inout_opt_ message< _Source_type > *_PMessage, _Inout_opt_ ISource< _Source_type > *_PSource)
Asynchronously passes a message from a source block to this target block.
Definition: agents.h:5640
virtual void propagate_to_any_targets(_Inout_opt_ message< _Destination_type > *)
Takes the message and propagates it to all the targets of this join block.
Definition: agents.h:12231
volatile bool _M_fIsInitialized
Definition: agents.h:10561
_Type const & const_reference
Definition: agents.h:262
A class intended to be used as a base class for all independent agents. It is used to hide state from...
Definition: agents.h:13273
An event type that represents the conclusion of some processing
Definition: concrt.h:5661
_MessageArray(size_t _NumInputs)
Definition: agents.h:9911
#define _In_z_
Definition: sal.h:310
message_status
The valid responses for an offer of a message object to a block.
Definition: agents.h:1740
virtual void link_target_notification(_Inout_ ITarget< _Type > *_PTarget)
A callback that notifies that a new target has been linked to this timer messaging block...
Definition: agents.h:8432
bool send(_Inout_ ITarget< _Type > *_Trg, const _Type &_Data)
A synchronous send operation, which waits until the target either accepts or declines the message...
Definition: agents.h:4337
#define _In_
Definition: sal.h:305
runtime_object_identity msg_id() const
Returns the ID of the message object.
Definition: agents.h:1861
virtual void _Reset()
Resets the _Reserving_node and prepares it for the next propagation
Definition: agents.h:10386
Definition: utility:367
volatile long _M_refCount
Definition: agents.h:1913
void _Invoke_unlink_source(ITarget< _Type > *_PUnlinkFrom)
Unlinks this source from a target.
Definition: agents.h:2773
_Call_method _M_pFunc
Definition: agents.h:7448
virtual void link_target(_Inout_ ITarget< size_t > *_PTarget)
Links a target block to this choice messaging block.
Definition: agents.h:11627
#define _Inout_opt_
Definition: sal.h:376
virtual message< _Target_type > * accept_message(runtime_object_identity _MsgId)=0
When overridden in a derived class, accepts an offered message by the source. Message blocks should o...
_Message * _Dequeue()
Definition: agents.h:204
message< _Type > * _M_pMessage
Definition: agents.h:9094
This class describes an exception thrown when an operation has timed out.
Definition: concrt.h:1712
message(_In_ message const *_Msg)
Constructs a message object.
Definition: agents.h:1840
_SourceLinkRegistry::type::source_type _Source_type
The type of the payload for the incoming messages to this target_block object.
Definition: agents.h:4453
_Join_node(ScheduleGroup &_PScheduleGroup)
Constructs a join within the specified schedule group. The scheduler is implied by the schedule group...
Definition: agents.h:12048
virtual message_status propagate_message(message< _Type > *_PMessage, ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this ITarget block. It is invoked by the pro...
Definition: agents.h:10416
single_link_registry< ITarget< size_t > > _TargetLinkRegistry
Definition: agents.h:10585
::Concurrency::details::_Queue< message< std::vector< _Type > > > _M_messageBuffer
Definition: agents.h:9959
runtime_object_identity _M_reservedId
Definition: agents.h:11385
single_link_registry< ITarget< size_t > > _TargetLinkRegistry
Definition: agents.h:10979
virtual message< _Type > * consume(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3591
virtual void propagate_to_any_targets(_Inout_opt_ message< _Type > *_PMessage)
Places the message _PMessage in this single_assignment messaging block and offers it to all of the l...
Definition: agents.h:9050
virtual void unlink_targets()
When overridden in a derived class, unlinks all target blocks from this ISource block.
Definition: agents.h:4018
Definition: agents.h:4267
overwrite_buffer()
Constructs an overwrite_buffer messaging block.
Definition: agents.h:6549
_CONCRTIMP bool start()
Moves an agent from the agent_created state to the agent_runnable state, and schedules it for executi...
An overwrite_buffer messaging block is a multi-target, multi-source, ordered propagator_block capable...
Definition: agents.h:6526
Definition: agents.h:9906
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:6530
The target_block class is an abstract base class that provides basic link management functionality an...
Definition: agents.h:4446
void start()
Starts the timer messaging block. The specified number of milliseconds after this is called...
Definition: agents.h:8277
virtual void link_target_notification(_Inout_ ITarget< _Target_type > *)
A callback that notifies that a new target has been linked to this source_block object.
Definition: agents.h:5241
virtual void acquire_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, acquires a reference count on this ISource block, to prevent deletion.
Definition: agents.h:4158
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this transformer messaging block.
Definition: agents.h:7873
transformer(_Transform_method const &_Func, _Inout_opt_ ITarget< _Output > *_PTarget=NULL)
Constructs a transformer messaging block.
Definition: agents.h:7512
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:9020
virtual void acquire_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, acquires a reference count on this ISource block, to prevent deletion.
Definition: agents.h:3604
virtual message< _Type > * consume(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3813
virtual void unlink_target(_Inout_ ITarget< _Destination_type > *_PTarget)
Unlinks a target block from this multitype_join messaging block.
Definition: agents.h:12753
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:6292
_Unwrap< _Type >::type _Destination_type
Definition: agents.h:12585
transformer const & operator=(transformer const &)
virtual void link_target_notification(_Inout_ ITarget< _Destination_type > *)
Notification that a target was linked to this source.
Definition: agents.h:12215
~choice()
Destroys the choice messaging block.
Definition: agents.h:11555
_Type value()
Gets a reference to the current payload of the message being stored in the overwrite_buffer messaging...
Definition: agents.h:6716
bool _M_fRepeating
Definition: agents.h:8471
bool _M_fDeclineMessages
A bool that is set to indicate that all messages should be declined in preparation for deleting the b...
Definition: agents.h:4848
virtual bool reserve_message(runtime_object_identity _MsgId)=0
When overridden in a derived class, reserves a message previously offered by this source_block object...
volatile long _M_queuedDataCount
A count of the current number of messages to process. Used as a flag to see if a new process message ...
Definition: agents.h:2391
::Concurrency::details::_ReentrantPPLLock _M_internalLock
Definition: agents.h:3964
virtual void _Fire()
Called when the timer fires.
Definition: agents.h:8492
virtual message< _Type > * consume(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:4104
void wait_for_async_sends()
Waits for all asynchronous propagations to complete.
Definition: agents.h:4800
::Concurrency::details::_ReentrantPPLLock::_Scoped_lock _R_lock
A lock holder that acquires a reentrant lock on instantiation and releases it on destruction ...
Definition: agents.h:65
static _CONCRTIMP void __cdecl wait_for_all(size_t _Count, _In_reads_(_Count) agent **_PAgents, _Out_writes_opt_(_Count) agent_status *_PStatus=NULL, unsigned int _Timeout=COOPERATIVE_TIMEOUT_INFINITE)
Waits for all of the specified agents to complete their tasks.
_SavedMessageIdArray(size_t _NumInputs)
Definition: agents.h:9938
std::vector< _Type > _OutputType
Definition: agents.h:9164
_Type type
A type alias for _Type .
Definition: agents.h:2539
This class describes an exception thrown when a messaging block is unable to find a requested message...
Definition: concrt.h:1544
virtual void acquire_ref(_Inout_ ITarget< size_t > *_PTarget)
Acquires a reference count on this choice messaging block, to prevent deletion.
Definition: agents.h:11748
virtual void unlink_targets()
Unlinks all targets from this choice messaging block.
Definition: agents.h:11652
long remove_ref()
Subtracts from the reference count for the message object. Used for message blocks that need referenc...
Definition: agents.h:1893
Definition: concrt.h:5341
multi_link_registry< ISource< size_t > > _SourceLinkRegistry
Definition: agents.h:12010
~call()
Destroys the call messaging block.
Definition: agents.h:7311
virtual void unlink_target_notification(_Inout_ ITarget< _Target_type > *_PTarget)
A callback that notifies that a target has been unlinked from this source_block object.
Definition: agents.h:5257
_Type type
A type alias for _Type .
Definition: agents.h:12728
void remove_sources()
Unlinks all sources after waiting for outstanding asynchronous send operations to complete...
Definition: agents.h:4815
_Type const payload
The payload of the message object.
Definition: agents.h:1870
The target tried to accept the message, but it was no longer available.
Definition: agents.h:1761
void _Initialize_joins()
Constructs and initializes a _Order_node for each tuple messaging block passed in.
Definition: agents.h:12894
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:10586
::Concurrency::details::_ReentrantPPLLock _M_internalLock
Definition: agents.h:4259
message< _Type > ** _M_messages
Definition: agents.h:9909
The target accepted the message.
Definition: agents.h:1746
multi_link_registry< ISource< _Input > > _SourceLinkRegistry
Definition: agents.h:7484
message< _Type > * _M_pMessage
Definition: agents.h:3955
single_link_registry< ITarget< _Destination_type > > _TargetLinkRegistry
Definition: agents.h:12009
multi_link_registry< ITarget< _Type > > _TargetLinkRegistry
Definition: agents.h:5920
virtual _CONCRTIMP ~agent()
Destroys the agent.
void enable_batched_processing()
Enables batched processing for this block.
Definition: agents.h:5396
_SyncOriginator()
Definition: agents.h:3694
volatile long _M_fCancelable
Definition: agents.h:13505
_CONCRTIMP ISource< agent_status > * status_port()
An asynchronous source of status information from the agent.
An event type that represents the scheduling of a process
Definition: concrt.h:5673
_Type const & value()
Gets a reference to the current payload of the message being stored.
Definition: agents.h:10024
::Concurrency::details::_ReentrantPPLLock _M_internalLock
Internal lock used for the following synchronization:
Definition: agents.h:5546
::Concurrency::details::_NonReentrantPPLLock::_Scoped_lock _NR_lock
A lock holder that acquires a non-reentrant lock on instantiation and releases it on destruction...
Definition: agents.h:58
volatile long _M_refcount
Definition: agents.h:4256
ScheduleGroup * _M_pScheduleGroup
Definition: agents.h:12984
virtual void acquire_ref(_Inout_ ITarget< _Target_type > *)
Acquires a reference count on this source_block object, to prevent deletion.
Definition: agents.h:5192
A join messaging block is a single-target, multi-source, ordered propagator_block which combines toge...
Definition: agents.h:9152
void _Sync_send_helper(message< _Type > *_Msg)
Definition: agents.h:2243
virtual ~_SyncOriginator()
Definition: agents.h:3702
virtual void link_target(ITarget< _Type > *_PTarget)
Definition: agents.h:3911
message< _Type > * _M_pReservedMessage
Definition: agents.h:7078
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:12501
The ISource class is the interface for all source blocks. Source blocks propagate messages to ITarget...
Definition: agents.h:452
_MessageProcessorType _M_messageProcessor
The message_processor for this target_block.
Definition: agents.h:4854
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:8419
_Type type
A type alias for _Type .
Definition: agents.h:2028
_SourceLinkManager _M_connectedSources
The container for all the sources connected to this block.
Definition: agents.h:5883
bool has_value() const
Checks whether this choice messaging block has been initialized with a value yet. ...
Definition: agents.h:11574
single_link_registry< ITarget< _Type > > _Target_registry
Definition: agents.h:3691
virtual message_status propagate_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this unbounded_buffer messaging block...
Definition: agents.h:6138
virtual message< size_t > * consume_message(runtime_object_identity)
Consumes a message previously offered by the source and reserved by the target, transferring ownershi...
Definition: agents.h:10077
virtual void propagate_to_any_targets(_Inout_opt_ message< size_t > *)
Takes the message and propagates it to all the targets of this _Order_node
Definition: agents.h:10500
void initialize_target(_Inout_opt_ Scheduler *_PScheduler=NULL, _Inout_opt_ ScheduleGroup *_PScheduleGroup=NULL)
Initializes the base object. Specifically, the message_processor object needs to be initialized...
Definition: agents.h:4738
#define false
Definition: stdbool.h:16
_Greedy_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Greedy_node within the specified schedule group. The scheduler is implied by the schedu...
Definition: agents.h:10709
_Non_greedy_node const & operator=(_Non_greedy_node const &)
virtual void unlink_target(ITarget< _Type > *_PTarget)
Definition: agents.h:3548
virtual void unlink_sources()
Unlinks all source blocks from this propagator_block object.
Definition: agents.h:5791
bool enqueue(_Type const &_Item)
Adds an item to the unbounded_buffer messaging block.
Definition: agents.h:6099
virtual void unlink_targets()
Unlinks all target blocks from this source_block object.
Definition: agents.h:4978
void * _InterlockedCompareExchangePointer(void *volatile *, void *, void *)
const unsigned int COOPERATIVE_TIMEOUT_INFINITE
Value indicating that a wait should never time out.
Definition: concrt.h:3478
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this unbounded_buffer messaging block.
Definition: agents.h:6246
virtual message< _Destination_type > * accept_message(runtime_object_identity _MsgId)
Accepts an offered message by the source, transferring ownership to the caller.
Definition: agents.h:12123
ScheduleGroup * _M_pScheduleGroup
The schedule group to process messages on
Definition: agents.h:2403
virtual void link_target(_Inout_ ITarget< _Target_type > *_PTarget)
Links a target block to this source_block object.
Definition: agents.h:4932
bool _M_fReferencedScheduler
Definition: agents.h:8474
_Greedy_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Greedy_node within the specified scheduler, and places it on any schedule group of the ...
Definition: agents.h:10657
virtual void acquire_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, acquires a reference count on this ISource block, to prevent deletion.
Definition: agents.h:3853
_CONCRTIMP _Timer(unsigned int _Ms, bool _FRepeating)
message_status _Propagate_to_target(ITarget< size_t > *_PTarget)
Propagate messages to the given target
Definition: agents.h:10520
long _Process_message_helper()
Definition: agents.h:2273
void initialize_source(_Inout_opt_ Scheduler *_PScheduler=NULL, _Inout_opt_ ScheduleGroup *_PScheduleGroup=NULL)
Initializes the message_propagator within this source_block.
Definition: agents.h:5382
_CONCRTIMP bool cancel()
Moves an agent from either the agent_created or agent_runnable states to the agent_canceled state...
bool has_value() const
Checks whether this block has been initialized yet.
Definition: agents.h:10012
_Type const & value()
Gets a reference to the current payload of the message being stored in the single_assignment messagin...
Definition: agents.h:8776
An event type that represents the initiation of some processing
Definition: concrt.h:5655
An event type that represents the deletion of an object
Definition: concrt.h:5667
message< size_t > * _M_pSendMessage
Definition: agents.h:10170
void Trace_agents_register_name(_Inout_ _Type *_PObject, _In_z_ const wchar_t *_Name)
Associates the given name to the message block or agent in the ETW trace.
Definition: agents.h:13534
virtual void link_target_notification(_Inout_ ITarget< _Type > *_PTarget)
A callback that notifies that a new target has been linked to this unbounded_buffer messaging block...
Definition: agents.h:6315
~unbounded_buffer()
Destroys the unbounded_buffer messaging block.
Definition: agents.h:6080
virtual void async_send(_Inout_opt_ message< _Type > *_Msg)
Asynchronously queues up messages and starts a processing task, if this has not been done already...
Definition: agents.h:2127
_CONCRTIMP agent()
Constructs an agent.
virtual void release_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, releases a reference count on this ISource block.
Definition: agents.h:3858
::Concurrency::details::_NonReentrantPPLLock _M_propagationLock
Definition: agents.h:10948
agent_status
The valid states for an agent.
Definition: agents.h:13237
multi_link_registry< ITarget< _Type > > _TargetLinkRegistry
Definition: agents.h:6529
bool _internal_send(ITarget< _Type > *_PTarget, _Type const &_Value)
Definition: agents.h:4181
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:7906
_Join_node< _Type, _Destination_type, _Jtype > * _M_pJoinNode
Definition: agents.h:12975
unbounded_buffer const & operator=(unbounded_buffer const &)
virtual void unlink_targets()
Unlinks all targets from this multitype_join messaging block.
Definition: agents.h:12762
_Non_greedy_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Non_greedy_node within the specified schedule group. The scheduler is implied by the sc...
Definition: agents.h:11135
volatile size_t _M_messagesRemaining
Definition: agents.h:9902
_Type _M_value
Definition: agents.h:8468
~_Dynamic_array()
Definition: agents.h:275
_Non_greedy_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Non_greedy_node within the default scheduler, and places it on any schedule group of th...
Definition: agents.h:11027
virtual message< _Output > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the transformer and reserved by the target, transferring ownership to the caller.
Definition: agents.h:7893
bool _Remove(_Message *_OldElement)
Definition: agents.h:156
void _Propagate_priority_order(::Concurrency::details::_Queue< message< _Target_type >> &_MessageBuffer)
Propagates messages in priority order.
Definition: agents.h:6408
virtual void link_target_notification(_Inout_ ITarget< size_t > *)
Notification that a target was linked to this source.
Definition: agents.h:10118
Definition: tuple:226
void _Acquire_ref()
Definition: agents.h:4236
typename std::remove_pointer_t< std::tuple_element_t< _Index, _Type >>::source_type _Source_type
Definition: agents.h:12881
_CONCRTIMP bool done()
Moves an agent into the agent_done state, indicating that the agent has completed.
void _Create_send_message()
Create a message that contains an index used to determine the source message
Definition: agents.h:10130
virtual void initialize_batched_processing(_Handler_method const &_Processor, _Propagator_method const &_Propagator)
Initialize batched message processing
Definition: agents.h:2095
virtual ::Concurrency::runtime_object_identity _GetId() const
Definition: agents.h:94
virtual message_status propagate_message(message< _Type > *_PMessage, ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this ITarget block. It is invoked by the pro...
Definition: agents.h:10846
_Target_registry _M_connectedTargets
Definition: agents.h:3967
message * _M_pNext
Definition: agents.h:1907
void register_filter(filter_method const &_Filter)
Registers a filter method that will be invoked on every message received.
Definition: agents.h:4705
constexpr auto data(_Container &_Cont) -> decltype(_Cont.data())
Definition: xutility:1513
A single_assignment messaging block is a multi-target, multi-source, ordered propagator_block capable...
Definition: agents.h:8587
virtual void unlink_target(ITarget< _Type > *_PTarget)
Definition: agents.h:3712
_CONCRTIMP size_t wait(unsigned int _Timeout=COOPERATIVE_TIMEOUT_INFINITE)
Waits for the event to become signaled.
bool _internal_send(ITarget< _Type > *_PTarget, _Type const &_Value)
Definition: agents.h:3618
_Handler_method _M_handler
A message handler object which exposes the callback to be invoked
Definition: agents.h:2422
_SourceLinkManager _M_connectedSources
The container for all the sources connected to this block.
Definition: agents.h:4835
virtual void release(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:4136
State
Tracks the state machine of the timer.
Definition: agents.h:8121
Base class for Helper node used in multi-type join and choice blocks Order node is a single-target...
Definition: agents.h:9978
_Non_greedy_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Non_greedy_node within the default scheduler, and places it on any schedule group of th...
Definition: agents.h:11002
void wait_for_outstanding_async_sends()
Waits for all asynchronous propagations to complete. This propagator-specific spin wait is used in de...
Definition: agents.h:5445
size_t _M_index
Definition: agents.h:10173
void _Invoke_handler(long _Count)
Definition: agents.h:2320
transformer(_Transform_method const &_Func, _Inout_opt_ ITarget< _Output > *_PTarget, filter_method const &_Filter)
Constructs a transformer messaging block.
Definition: agents.h:7548
_Type type
A type alias for _Type .
Definition: agents.h:11565
virtual message< _Destination_type > * accept(runtime_object_identity _MsgId, _Inout_ ITarget< _Destination_type > *_PTarget)
Accepts a message that was offered by this multitype_join block, transferring ownership to the caller...
Definition: agents.h:12780
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:8044
virtual void unlink_targets()=0
When overridden in a derived class, unlinks all target blocks from this ISource block.
Scheduler * _M_pScheduler
Definition: agents.h:8477
virtual void unlink_targets()
When overridden in a derived class, unlinks all target blocks from this ISource block.
Definition: agents.h:3733
_SourceLinkManager::iterator source_iterator
The type of the iterator for the source_link_manager for this propagator_block.
Definition: agents.h:5596
runtime_object_identity * _M_savedIdBuffer
Definition: agents.h:9953
runtime_object_identity _M_reservedId
Reserved message ID
Definition: agents.h:5478
_Type receive(_Inout_ ISource< _Type > *_Src, unsigned int _Timeout=COOPERATIVE_TIMEOUT_INFINITE)
A general receive implementation, allowing a context to wait for data from exactly one source and fil...
Definition: agents.h:3063
virtual message< _Type > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the unbounded_buffer messaging block and reserved by the tar...
Definition: agents.h:6266
virtual void link_target(ITarget< _Type > *_PTarget)
Definition: agents.h:3673
ITarget< _Type > * _M_pTarget
Definition: agents.h:3682
std::function< void(message< _Type > *)> _Handler_method
The signature of the callback method invoked while processing messages.
Definition: agents.h:2016
size_t _M_count
Definition: agents.h:9908
message< _Destination_type > * _Create_send_message()
Called when all the source messaging blocks have received their messages. The payloads are copied int...
Definition: agents.h:12449
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:7919
virtual message_status propagate_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this call messaging block. It is invoked by the propagate method, when called by a source block.
Definition: agents.h:7337
message< _Type > * _NewMessage() const
Allocates a new message.
Definition: agents.h:8483
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:9533
_CONCRTIMP void set()
Signals the event.
virtual void link_target(ITarget< _Type > *_PTarget)
Definition: agents.h:4218
void _Initialize(size_t _NumInputs, Scheduler *_PScheduler=NULL, ScheduleGroup *_PScheduleGroup=NULL)
Initializes the join messaging block.
Definition: agents.h:9856
void initialize(_Inout_opt_ Scheduler *_PScheduler, _Inout_opt_ ScheduleGroup *_PScheduleGroup, _Handler_method const &_Handler)
Initializes the ordered_message_processor object with the appropriate callback function, scheduler and schedule group.
Definition: agents.h:2078
virtual void release_ref(_Inout_ ITarget< _Type > *)
When overridden in a derived class, releases a reference count on this ISource block.
Definition: agents.h:4163
virtual void propagate_to_any_targets(_Inout_opt_ message< _Type > *)
Tries to offer the message produced by the timer block to all of the linked targets.
Definition: agents.h:8446
_Reserving_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Order_node within the specified schedule group. The scheduler is implied by the schedul...
Definition: agents.h:10325
volatile message_status _M_fStatus
Definition: agents.h:3961
virtual void release(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3831
void initialize_source_and_target(_Inout_opt_ Scheduler *_PScheduler=NULL, _Inout_opt_ ScheduleGroup *_PScheduleGroup=NULL)
Initializes the base object. Specifically, the message_processor object needs to be initialized...
Definition: agents.h:5826
long __cdecl _InterlockedDecrement(long volatile *)
A choice messaging block is a multi-source, single-target block that represents a control-flow intera...
Definition: agents.h:11420
virtual message_status propagate_message(message< _Type > *_PMessage, ISource< _Type > *)
Asynchronously passes a message from an ISource block to this ITarget block. It is invoked by the pro...
Definition: agents.h:11300
virtual message< _Type > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this timer messaging block, transferring ownership to the calle...
Definition: agents.h:8337
void _Wait_on_ref(long _RefCount=0)
Definition: agents.h:5528
virtual message_status propagate(_Inout_opt_ message< _Type > *_PMessage, _Inout_opt_ ISource< _Type > *_PSource)=0
When overridden in a derived class, asynchronously passes a message from a source block to this targe...
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:9882
filter_method * _M_pFilter
The filter function which determines whether offered messages should be accepted. ...
Definition: agents.h:5889
~overwrite_buffer()
Destroys the overwrite_buffer messaging block.
Definition: agents.h:6684
virtual void process_input_messages(_Inout_ message< _Type > *_PMessage)
Executes the call function on the input messages.
Definition: agents.h:7433
~_SavedMessageIdArray()
Definition: agents.h:9945
static bool _asend(ITarget< _Type > *_Trg, const _Type &_Data)
Definition: agents.h:4294
virtual bool reserve(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:4082
#define _CONCRTIMP
Definition: crtdefs.h:48
virtual void propagate_to_any_targets(_Inout_opt_ message< size_t > *)
Takes the message and propagates it to all the targets of this _Greedy_node
Definition: agents.h:10920
virtual void release_message(runtime_object_identity)
Releases a previous message reservation.
Definition: agents.h:10092
single_assignment const & operator=(single_assignment const &)
void * _M_pSourceJoins[std::tuple_size< _Type >::value]
Definition: agents.h:12972
std::function< bool(_Type const &)> filter_method
The signature of any method used by the block that returns a bool value to determine whether an offer...
Definition: agents.h:2546
#define _In_reads_(size)
Definition: sal.h:316
virtual void unlink_targets()
When overridden in a derived class, unlinks all target blocks from this ISource block.
Definition: agents.h:3554
_AsyncOriginator()
Definition: agents.h:4174
virtual message_status send(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)=0
When overridden in a derived class, synchronously passes a message to the target block.
virtual message< size_t > * accept_message(runtime_object_identity _MsgId)
Accept the message by making a copy of the payload.
Definition: agents.h:10890
void _Release_ref()
Definition: agents.h:4243
_Greedy_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Greedy_node within the default scheduler, and places it on any schedule group of the sc...
Definition: agents.h:10632
Definition: concrt.h:279
_Myt & operator=(const _Myt &_Right)
Definition: agents.h:283
single_link_registry< ITarget< std::vector< _Type > > > _TargetLinkRegistry
Definition: agents.h:9155
call(_Call_method const &_Func)
Constructs a call messaging block.
Definition: agents.h:7143
#define _Inout_
Definition: sal.h:375
virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget< size_t > *_PTarget)
Reserves a message previously offered by this choice messaging block.
Definition: agents.h:11694
virtual bool reserve_message(runtime_object_identity)
Reserves a message previously offered by the source.
Definition: agents.h:10055
_Type _Receive_impl(ISource< _Type > *_Src, unsigned int _Timeout, typename ITarget< _Type >::filter_method const *_Filter_proc)
A general receive implementation, allowing a context to wait for data from exactly one source and fil...
Definition: agents.h:2808
void register_filter(filter_method const &_Filter)
Registers a filter method that will be invoked on every received message.
Definition: agents.h:5841
void _Propagate_priority_order(::Concurrency::details::_Queue< message< _Target_type >> &_MessageBuffer)
Propagate messages in priority order
Definition: agents.h:12396
virtual message_status send(_Inout_ message< _Source_type > *_PMessage, _Inout_ ISource< _Source_type > *_PSource)
Synchronously initiates a message to this block. Called by an ISource block. When this function compl...
Definition: agents.h:5688
~_Queue()
Definition: agents.h:127
_CONCRTIMP unsigned int _Reference()
virtual void link_target_notification(_Inout_ ITarget< _Type > *_PTarget)
A callback that notifies that a new target has been linked to this single_assignment messaging block...
Definition: agents.h:9033
virtual void propagate_output_messages()
Places the message _PMessage in this unbounded_buffer messaging block and tries to offer it to all o...
Definition: agents.h:6368
volatile bool _M_fIsInitialized
Definition: agents.h:7081
virtual message_status propagate_message(message< size_t > *_PMessage, ISource< size_t > *_PSource)
Asynchronously passes a message from an ISource block to this ITarget block. It is invoked by the pro...
Definition: agents.h:12083
virtual void process_incoming_message()
The processing function that is called asynchronously. It dequeues messages and begins processing the...
Definition: agents.h:2218
virtual message_status propagate_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this overwrite_buffer messaging block...
Definition: agents.h:6742
_Non_greedy_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Non_greedy_node within the specified schedule group. The scheduler is implied by the sc...
Definition: agents.h:11107
virtual message_status propagate_message(_Inout_ message< _Input > *_PMessage, _Inout_ ISource< _Input > *_PSource)
Asynchronously passes a message from an ISource block to this transformer messaging block...
Definition: agents.h:7756
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:7043
_CRT_BEGIN_C_HEADER typedef void(__CRTDECL *unexpected_handler)()
runtime_object_identity _M_savedId
Definition: agents.h:10955
_Message * _M_pHead
Definition: agents.h:110
Defines a block allowing sources of distinct types to be joined. Join node is a single-target, multi-source ordered propagator block
Definition: agents.h:12006
concurrent_queue< message< _Input > * > _M_inputMessages
Definition: agents.h:8077
virtual void link_target_notification(_Inout_ ITarget< _Type > *_PTarget)
A callback that notifies that a new target has been linked to this overwrite_buffer messaging block...
Definition: agents.h:6980
_Greedy_node(ScheduleGroup &_PScheduleGroup, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Greedy_node within the specified schedule group. The scheduler is implied by the schedu...
Definition: agents.h:10736
const_reference operator[](size_t _Pos) const
Definition: agents.h:345
~_Greedy_node()
Cleans up any resources that may have been created by the _Greedy_node.
Definition: agents.h:10748
source_link_manager< _SourceLinkRegistry > _SourceLinkManager
The type of the source_link_manager this propagator_block.
Definition: agents.h:5590
void _Init()
Definition: agents.h:385
void remove_network_links()
Removes all the source and target network links from this propagator_block object.
Definition: agents.h:5865
void _Delete_stored_messages()
Deletes all messages currently stored in this message block. Should be called by the destructor to en...
Definition: agents.h:6461
single_assignment< size_t > * _M_pSingleAssignment
Definition: agents.h:11837
_Message type
Definition: agents.h:119
void _Reset()
Resets the _Order_node and prepares it for the next propagation
Definition: agents.h:11168
_Join_node()
Constructs a join within the default scheduler, and places it on any schedule group of the scheduler'...
Definition: agents.h:12022
_SavedMessageIdArray _M_savedMessageIdArray
Definition: agents.h:9950
virtual message< _Type > * accept_message(runtime_object_identity _MsgId)
Accepts a message that was offered by this unbounded_buffer messaging block, transferring ownership t...
Definition: agents.h:6216
virtual message_status send_message(_Inout_ message< _Source_type > *, _Inout_ ISource< _Source_type > *)
When overridden in a derived class, this method synchronously passes a message from an ISource block ...
Definition: agents.h:4624
A call messaging block is a multi-source, ordered target_block that invokes a specified function when...
Definition: agents.h:7111
ITarget< _Target_type > * _M_pReservedFor
Connected target that is holding a reservation
Definition: agents.h:5472
~timer()
Destroys a timer messaging block.
Definition: agents.h:8247
virtual ~propagator_block()
Destroys a propagator_block object.
Definition: agents.h:5613
long __cdecl _InterlockedIncrement(long volatile *)
join(size_t _NumInputs, filter_method const &_Filter)
Constructs a join messaging block.
Definition: agents.h:9208
bool asend(ITarget< _Type > &_Trg, const _Type &_Data)
An asynchronous send operation, which schedules a task to propagate the value to the target block...
Definition: agents.h:4423
virtual void propagate_to_any_targets(_Inout_opt_ message< _Target_type > *_PMessage)
When overridden in a derived class, propagates the given message to any or all of the linked targets...
Definition: agents.h:5362
virtual void release(runtime_object_identity _MsgId, ITarget< _Type > *_PTarget)
Definition: agents.h:3599
virtual ~message()
Destroys the message object.
Definition: agents.h:1852
call const & operator=(call const &)
virtual void resume_propagation()
Resumes propagation after a reservation has been released.
Definition: agents.h:9546
virtual message_status send_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Synchronously passes a message from an ISource block to this overwrite_buffer messaging block...
Definition: agents.h:6786
virtual message_status send_message(_Inout_ message< _Source_type > *, _Inout_ ISource< _Source_type > *)
When overridden in a derived class, this method synchronously passes a message from an ISource block ...
Definition: agents.h:5750
source_block()
Constructs a source_block object.
Definition: agents.h:4899
_Transform_method _M_pFunc
Definition: agents.h:8074
const size_t COOPERATIVE_WAIT_TIMEOUT
Value indicating that a wait timed out.
Definition: concrt.h:3469
single_link_registry< ITarget< _Type > > _TargetLinkRegistry
Definition: agents.h:8112
_Dynamic_array< _Type > _Myt
Definition: agents.h:259
_CONCRTIMP::Concurrency::Scheduler * _GetScheduler()
Definition: concrt.h:382
message< _Type > * _M_pMessage
Definition: agents.h:4253
long add_ref()
Adds to the reference count for the message object. Used for message blocks that need reference count...
Definition: agents.h:1880
virtual void unlink_sources()=0
When overridden in a derived class, unlinks all source blocks from this ITarget block.
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:6279
virtual void wait()=0
When overridden in a derived class, waits for all asynchronous operations to complete.
#define SIZE_MAX
Definition: limits.h:76
_Order_node_base()
Constructs a _Order_node_base within the default scheduler, and places it on any schedule group of th...
Definition: agents.h:9986
::Concurrency::details::_ReentrantPPLLock _M_resetLock
Definition: agents.h:11379
virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget< _Target_type > *_PTarget)
Reserves a message previously offered by this source_block object.
Definition: agents.h:5052
bool _Try_receive_impl(ISource< _Type > *_Src, _Type &_value, typename ITarget< _Type >::filter_method const *_Filter_proc)
Helper function that implements try_receive A general try-receive implementation, allowing a context ...
Definition: agents.h:3199
_Handler_method _M_processor
A message processing object which exposes the callback to be invoked
Definition: agents.h:2428
virtual message< _Type > * consume(runtime_object_identity _MsgId, _Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, consumes a message previously offered by this ISource block and s...
virtual bool reserve(runtime_object_identity _MsgId, _Inout_ ITarget< _Destination_type > *_PTarget)
Reserves a message previously offered by this multitype_join messaging block.
Definition: agents.h:12804
::Concurrency::details::_Queue< message< _Type > > _M_messageBuffer
Message queue used to store messages
Definition: agents.h:6490
virtual message_status send(_Inout_ message< _Source_type > *_PMessage, _Inout_ ISource< _Source_type > *_PSource)
Synchronously passes a message from a source block to this target block.
Definition: agents.h:4562
void sync_send(_Inout_opt_ message< _Source_type > *_PMessage)
Synchronously send a message for processing.
Definition: agents.h:4787
bool has_value() const
Checks whether this overwrite_buffer messaging block has a value yet.
Definition: agents.h:6700
_In_ int _Value
Definition: setjmp.h:173
ordered_message_processor()
Constructs an ordered_message_processor object.
Definition: agents.h:2038
virtual void release_ref(_Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, releases a reference count on this ISource block.
virtual ~ITarget()
Destroys the ITarget object.
Definition: agents.h:2468
virtual message< _Destination_type > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the source and reserved by the target, transferring ownershi...
Definition: agents.h:12173
virtual void process_message(message< _Source_type > *)
When overridden in a derived class, processes a message that was accepted by this target_block object...
Definition: agents.h:4689
static void __cdecl _Process_incoming_message_wrapper(void *_Data)
Wrapper for process_incoming_message suitable for use as a argument to CreateThread and other similar...
Definition: agents.h:1993
virtual void process_input_messages(_Inout_ message< _Type > *_PMessage)
Places the message _PMessage in this unbounded_buffer messaging block and tries to offer it to all o...
Definition: agents.h:6346
::Concurrency::details::_NonReentrantPPLLock _M_propagationLock
Definition: agents.h:9956
long __cdecl _InterlockedCompareExchange(long volatile *, long, long)
single_link_registry< ITarget< _Type > > _Target_registry
Definition: agents.h:3978
virtual bool reserve_message(runtime_object_identity _MsgId)
Reserves a message previously offered by this timer messaging block.
Definition: agents.h:8364
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:9156
static const int _S_growthFactor
Definition: agents.h:427
virtual ~_AnonymousOriginator()
Definition: agents.h:3542
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:12186
::Concurrency::details::_NonReentrantPPLLock _M_propagationLock
Definition: agents.h:9097
A transformer messaging block is a single-target, multi-source, ordered propagator_block which can ac...
Definition: agents.h:7479
virtual void sync_send(_Inout_opt_ message< _Type > *_Msg)
Synchronously queues up messages and starts a processing task, if this has not been done already...
Definition: agents.h:2109
message< _Type > * _M_pMessage
Definition: agents.h:8462
void * _M_pSourceChoices[std::tuple_size< _Type >::value]
Definition: agents.h:11834
virtual void resume_propagation()
Resumes propagation after a reservation has been released
Definition: agents.h:10105
virtual void async_send(_Inout_opt_ message< _Type > *_Msg)=0
When overridden in a derived class, places messages into the block asynchronously.
virtual message< _Type > * consume_message(runtime_object_identity _MsgId)
Consumes a message previously offered by the overwrite_buffer messaging block and reserved by the tar...
Definition: agents.h:6913
void _Propagate_priority_order(::Concurrency::details::_Queue< message< _Target_type >> &_MessageBuffer)
Propagates messages in priority order.
Definition: agents.h:7991
filter_method * _M_pFilter
The filter function which determines whether offered messages should be accepted. ...
Definition: agents.h:4841
virtual message_status propagate(_Inout_opt_ message< _Source_type > *_PMessage, _Inout_opt_ ISource< _Source_type > *_PSource)
Asynchronously passes a message from a source block to this target block.
Definition: agents.h:4511
::Concurrency::details::_Queue< message< _Type > > _M_processedMessages
Message queue used to store processed messages
Definition: agents.h:6484
The concurrent_queue class is a sequence container class that allows first-in, first-out access to it...
Definition: concurrent_queue.h:55
virtual void unlink_target(ITarget< _Type > *_PTarget)
Definition: agents.h:3989
message(message const &_Msg)
Constructs a message object.
Definition: agents.h:1827
_Size
Definition: vcruntime_string.h:36
void _Grow(size_t _NewSize)
Definition: agents.h:395
multi_link_registry< ISource< _Type > > _SourceLinkRegistry
Definition: agents.h:8591
The propagator_block class is an abstract base class for message blocks that are both a source and ta...
Definition: agents.h:5577
_Reserving_node(Scheduler &_PScheduler, ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget, filter_method const &_Filter)
Constructs a _Reserving_node within the specified scheduler, and places it on any schedule group of t...
Definition: agents.h:10299
Greedy join messaging blocks immediately accept a message upon propagation. This is more efficient...
Definition: agents.h:9124
bool try_receive(_Inout_ ISource< _Type > *_Src, _Type &_value)
A general try-receive implementation, allowing a context to look for data from exactly one source and...
Definition: agents.h:3421
virtual void process_message(_Inout_ message< _Type > *_PMessage)
Processes a message that was accepted by this call messaging block.
Definition: agents.h:7424
constexpr const _Ty &() _Right
Definition: algorithm:3591
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:9006
virtual void async_send(_Inout_opt_ message< _Target_type > *_Msg)
Asynchronously queues up messages and starts a propagation task, if this has not been done already ...
Definition: agents.h:5434
The agent has been created but not started.
Definition: agents.h:13242
virtual void propagate_output_messages()
Propagate messages to targets.
Definition: agents.h:5349
void remove_targets()
Removes all target links for this source block. This should be called from the destructor.
Definition: agents.h:5454
multi_link_registry< ITarget< _Type > > _TargetLinkRegistry
Definition: agents.h:8590
std::function< _Output(_Input const &)> _Transform_method
Definition: agents.h:7482
bool _Try_consume_source_messages(_Destination_type &_Destination_tuple, ISource< size_t > **_Sources)
Tries to reserve from all sources. If successful, it will consume all the messages ...
Definition: agents.h:12285
virtual void release_ref(_Inout_ ITarget< _Destination_type > *_PTarget)
Releases a reference count on this multiple_join messaging block.
Definition: agents.h:12874
_Greedy_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Greedy_node within the default scheduler, and places it on any schedule group of the sc...
Definition: agents.h:10608
_Reserving_node(ISource< _Type > *_PSource, size_t _Index, ITarget< size_t > *_PTarget=NULL)
Constructs a _Reserving_node within the default scheduler, and places it on any schedule group of the...
Definition: agents.h:10220
The agent has started.
Definition: agents.h:13252
message< _Type > * _M_pGreedyMessage
Definition: agents.h:10945
virtual void acquire_ref(_Inout_ ITarget< _Type > *_PTarget)=0
When overridden in a derived class, acquires a reference count on this ISource block, to prevent deletion.
The agent was canceled.
Definition: agents.h:13262
Scheduler * _M_pScheduler
The scheduler to process messages on
Definition: agents.h:2397
virtual void wait()
A processor-specific spin wait used in destructors of message blocks to make sure that all asynchrono...
Definition: agents.h:2189
~transformer()
Destroys the transformer messaging block.
Definition: agents.h:7728
_AnonymousOriginator()
Definition: agents.h:3537
bool _Enqueue(_Message *_Element)
Definition: agents.h:140
timer(unsigned int _Ms, _Type const &_Value, ITarget< _Type > *_PTarget=NULL, bool _Repeating=false)
Constructs a timer messaging block that will fire a given message after a specified interval...
Definition: agents.h:8170
target_block()
Constructs a target_block object.
Definition: agents.h:4473
virtual message< size_t > * accept_message(runtime_object_identity _MsgId)
Accept the message by making a copy of the payload.
Definition: agents.h:10457
virtual void release_message(runtime_object_identity _MsgId)
Releases a previous message reservation.
Definition: agents.h:8404
The timer has been stopped.
Definition: agents.h:8142
#define _InterlockedIncrementSizeT(_Target)
Definition: concrt.h:96
volatile long _M_fStartable
Definition: agents.h:13498
_Order_node_base const & operator=(_Order_node_base const &)
static _CONCRTIMP _Scheduler __cdecl _Get()
static _CONCRTIMP void __cdecl wait_for_one(size_t _Count, _In_reads_(_Count) agent **_PAgents, agent_status &_Status, size_t &_Index, unsigned int _Timeout=COOPERATIVE_TIMEOUT_INFINITE)
Waits for any one of the specified agents to complete its task.
virtual void run()=0
Represents the main task of an agent. run should be overridden in a derived class, and specifies what the agent should do after it has been started.
virtual void unlink_target(_Inout_ ITarget< _Target_type > *_PTarget)
Unlinks a target block from this source_block object.
Definition: agents.h:4957
virtual message_status propagate_message(_Inout_ message< _Source_type > *_PMessage, _Inout_ ISource< _Source_type > *_PSource)=0
When overridden in a derived class, this method asynchronously passes a message from an ISource block...
message_status propagate_message(_Inout_ message< _Type > *_PMessage, _Inout_ ISource< _Type > *_PSource)
Asynchronously passes a message from an ISource block to this join messaging block. It is invoked by the propagate method, when called by a source block.
Definition: agents.h:9367