1. --  (c) Copyright, Real-Time Innovations, $Date:: 2012-02-16 #$ 
  2. --  All rights reserved. 
  3. -- 
  4. --  No duplications, whole or partial, manual or electronic, may be made 
  5. --  without express written permission.  Any such copies, or 
  6. --  revisions thereof, must display this notice unaltered. 
  7. --  This code contains trade secrets of Real-Time Innovations, Inc. 
  8.  
  9.  
  10. ------------------------------------------------------------------------------ 
  11. --  Allows an application to wait until one or more of the attached 
  12. --  DDS.Condition objects has a trigger_value 
  13. --  of true or else until the timeout expires. More .. . 
  14. --  This mechanism is wait-based. Its general use pattern is as follows: 
  15. -- 
  16. --   * The application indicates which relevant information it wants to get 
  17. --     by creating DDS.Condition objects 
  18. --    (DDS.StatusCondition, 
  19. --     DDS.ReadCondition or 
  20. --     DDS.QueryCondition) and attaching them to a DDS.WaitSet. 
  21. -- 
  22. --   * It then waits on that DDS.WaitSet until the trigger_value of one 
  23. --     or several DDS.Condition objects become true. 
  24. -- 
  25. --   * It then uses the result of the wait (i.e., active_conditions, 
  26. --     the list of DDS.Condition objects with trigger_value == true) 
  27. --     to actually get the information: 
  28. --       o by calling DDS.Entity.get_status_changes and then 
  29. --         get_<communication_status>() on the relevant DDS.Entity, 
  30. --         if the condition is a DDS.StatusCondition and the status changes, 
  31. --        refer to plain communication status; 
  32. -- 
  33. --       o by calling DDS.Entity.get_status_changes and then 
  34. --         DDS.Subscriber.get_datareaders on the relevant DDS.Subscriber 
  35. --         (and then DDS.topic.example.FooDataReader.read() 
  36. --          or DDS.topic.example.FooDataReader.take on the returned 
  37. --          DDS.DataReader objects), 
  38. --         if the condition is a DDS.StatusCondition and the status 
  39. --         changes refers to StatusKind.DATA_ON_READERS_STATUS; 
  40. -- 
  41. --       o by calling DDS.Entity.get_status_changes and then 
  42. --          DDS.topic.example.FooDataReader.read or 
  43. --          DDS.topic.example.FooDataReader.take on the 
  44. --           relevant DDS.DataReader, 
  45. --          if the condition is a DDS.StatusCondition and the 
  46. --          status changes refers to StatusKind.DATA_AVAILABLE_STATUS; 
  47. -- 
  48. --       o by calling directly DDS.topic.example.FooDataReader.read_w_condition 
  49. --         or DDS.topic.example.FooDataReader.take_w_condition on 
  50. --         a DDS.DataReader with the DDS.Condition as a parameter if it is a 
  51. --           DDS.ReadCondition or a  DDS.QueryCondition. 
  52. -- 
  53. --  Usually the first step is done in an initialization phase, 
  54. --  while the others are put in the application main loop. 
  55. -- 
  56. --  As there is no extra information passed from the middleware to the application 
  57. --  when a wait returns (only the list of triggered DDS.Condition objects), 
  58. --  DDS.Condition objects are meant to embed all that is needed to 
  59. --  react properly when enabled. 
  60. --  In particular, DDS.Entity-related conditions are related to exactly one 
  61. --  DDS.Entity and cannot be shared. 
  62. --  The result of a WaitSet.wait operation depends on the state of the DDS.WaitSet, 
  63. --  which in turn depends on whether at least one attached DDS.Condition has 
  64. --  a trigger_value of true. If the wait operation is called on DDS.WaitSet 
  65. --  with state BLOCKED, it will block the calling thread. 
  66. --  If wait is called on a DDS.WaitSet with state UNBLOCKED, 
  67. --  it will return immediately. 
  68. --  In addition, when the DDS.WaitSet transitions from BLOCKED to UNBLOCKED 
  69. --  it wakes up any threads that had called wait on it. 
  70. -- 
  71. --  A key aspect of the DDS.Condition/DDS.WaitSet mechanism is the setting of 
  72. --  the trigger_value of each DDS.Condition. 
  73. --  Trigger State of a DDS.StatusCondition 
  74. --  The trigger_value of a DDS.StatusCondition is the boolean OR of the 
  75. --  ChangedStatusFlag of all the communication statuses (see Status Kinds) 
  76. --  to which it is sensitive. 
  77. --  That is, trigger_value == false only if all the values of the 
  78. --  ChangedStatusFlags are false. 
  79. -- 
  80. --  The sensitivity of the DDS.StatusCondition to a particular communication 
  81. --  status is controlled by the list of enabled_statuses set on the condition 
  82. --  by means of the DDS.StatusCondition.set_enabled_statuses operation. 
  83. --  Trigger State of a DDS.ReadCondition 
  84. --  Similar to the DDS.StatusCondition, a DDS.ReadCondition also has a 
  85. --  trigger_value that determines whether the attached DDS.WaitSet is 
  86. --  BLOCKED or UNBLOCKED. 
  87. --  However, unlike the DDS.StatusCondition, the trigger_value of the 
  88. --  DDS.ReadCondition is tied to the presence of at least a sample managed by 
  89. --  Data Distribution Service with DDS.SampleStateKind and DDS.ViewStateKind 
  90. --  matching those of the DDS.ReadCondition. 
  91. --  Furthermore, for the DDS.QueryCondition to have a trigger_value == true, 
  92. --  the data associated with the sample must be such that the 
  93. --  query_expression evaluates to true. 
  94. -- 
  95. --  The fact that the trigger_value of a DDS.ReadCondition depends on 
  96. --  the presence of samples on the associated DDS.DataReader implies 
  97. --  that a single take operation can potentially change the trigger_value of 
  98. --  several DDS.ReadCondition or DDS.QueryCondition conditions. For example, 
  99. --  if all samples are taken, any DDS.ReadCondition and 
  100. --  DDS.QueryCondition conditions associated with the DDS.DataReader 
  101. --  that had their trigger_value==TRUE before will see the trigger_value 
  102. --  change to FALSE. Note that this does not guarantee that 
  103. --  DDS.WaitSet objects that were separately attached to 
  104. --  those conditions will not be woken up. 
  105. --  Once we have trigger_value==TRUE on a condition, 
  106. --  it may wake up the attached DDS.WaitSet, 
  107. --  the condition transitioning to trigger_value==FALSE 
  108. --  does not necessarily 'unwakeup' the WaitSet as 'unwakening' 
  109. --   may not be possible in general. 
  110. -- 
  111. --  The consequence is that an application blocked on a DDS.WaitSet 
  112. --  may return from the wait with a list of conditions, 
  113. --   some of which are not no longer 'active'. 
  114. --  This is unavoidable if multiple threads are concurrently 
  115. --  waiting on separate DDS.WaitSet objects and taking data 
  116. --  associated with the same DDS.DataReader entity. 
  117. -- 
  118. --  To elaborate further, consider the following example: 
  119. --   A DDS.ReadCondition that has a 
  120. --     sample_state_mask = {SampleStateKind.NOT_READ_SAMPLE_STATE} 
  121. --  will have trigger_value of true whenever a new sample arrives 
  122. --   and will transition to false as soon as all the newly-arrived 
  123. --   samples are either read (so their sample state changes to READ) 
  124. --   or taken (so they are no longer managed by the Data Distribution Service). 
  125. --  However if the same DDS.ReadCondition had a 
  126. --    sample_state_mask = { SampleStateKind.READ_SAMPLE_STATE, 
  127. --                          SampleStateKind.NOT_READ_SAMPLE_STATE }, 
  128. --  then the trigger_value would only become false once all the newly-arrived 
  129. --  samples are taken (it is not sufficient to read them as that would only 
  130. --  change the sample state to READ), 
  131. --  which overlaps the mask on the DDS.ReadCondition. 
  132. --  Trigger State of a DDS.GuardCondition 
  133. --  The trigger_value of a DDS.GuardCondition is completely controlled by 
  134. --  the application via the operation DDS.GuardCondition.set_trigger_value. 
  135. -- 
  136. --  Important: 
  137. --    The DDS.WaitSet allocates native resources. 
  138. --    When DDS.WaitSet is no longer being used, user should call 
  139. --    WaitSet.delete explicitly to properly cleanup all native resources. 
  140. ------------------------------------------------------------------------------ 
  141.  
  142. pragma Ada_05; 
  143. with Ada.Finalization; 
  144. with DDS.WaitSet_Impl; 
  145. with DDS.ConditionSeq; 
  146. with DDS.Condition; 
  147.  
  148. --  <dref>WaitSet</dref> 
  149. package DDS.WaitSet is 
  150.  
  151.    type Ref is new Ada.Finalization.Limited_Controlled with private; 
  152.    --  <dref>WaitSet_new</dref> 
  153.  
  154.    type Ref_Access is access all Ref'Class; 
  155.  
  156.    procedure Initialize 
  157.      (Self : in out Ref); 
  158.  
  159.    procedure Finalize 
  160.      (Self : in out Ref); 
  161.  
  162.    procedure Wait 
  163.      (Self              : not null access Ref; 
  164.       Active_Conditions : access DDS.ConditionSeq.Sequence; 
  165.       Timeout           : in DDS.Duration_T); 
  166.    --  <dref>WaitSet_wait</dref> 
  167.  
  168.    procedure Wait 
  169.      (Self              : not null access Ref; 
  170.       Active_Conditions : access DDS.ConditionSeq.Sequence; 
  171.       Timeout           : in Duration); 
  172.    --  <dref>WaitSet_wait</dref> 
  173.    --  <internal> 
  174.    --  Allows an application thread to wait for the occurrence of certain conditions. 
  175.    --  If none of the conditions attached to the dds.WaitSet have 
  176.    --  a trigger_value of true, the wait operation will block suspending the calling thread. 
  177.    --  The result of the wait operation is the list of all the attached conditions that have a trigger_value of true (i.e., the conditions that unblocked the wait). 
  178.    --  The wait operation takes a timeout argument that specifies the maximum duration for the wait. If this duration is exceeded and none of the attached com.rti.dds.infrastructure.Condition objects is true, wait will return with the return code RETCODE_TIMEOUT. In this case, the resulting list of conditions will be empty. 
  179.    --  RETCODE_TIMEOUT will not be returned when the timeout duration is exceeded if attached com.rti.dds.infrastructure.Condition objects are true, or in the case of a com.rti.dds.infrastructure.WaitSet waiting for more than one trigger event, if one or more trigger events have occurred. 
  180.    --  It is not allowable for for more than one application thread to be waiting on the same com.rti.dds.infrastructure.WaitSet. If the wait operation is invoked on a com.rti.dds.infrastructure.WaitSet that already has a thread blocking on it, the operation will return immediately with the value RETCODE_PRECONDITION_NOT_MET. 
  181.    --  </internal> 
  182.  
  183.    procedure Attach_Condition 
  184.      (Self : not null access Ref; 
  185.       Cond : access DDS.Condition.Ref'Class); 
  186.    --  <dref>WaitSet_attach_condition</dref> 
  187.  
  188.    procedure Detach_Condition 
  189.      (Self : not null access Ref; 
  190.       Cond : access DDS.Condition.Ref'Class); 
  191.    --  <dref>WaitSet_detach_condition</dref> 
  192.  
  193.    procedure Get_Conditions 
  194.      (Self                : not null access Ref; 
  195.       Attached_Conditions : access DDS.ConditionSeq.Sequence); 
  196.    --  <dref>WaitSet_get_conditions</dref> 
  197.  
  198.    procedure Free (This : in out Ref_Access); 
  199.    --  <dref>WaitSet_delete</dref> 
  200.  
  201.    procedure Set_Property 
  202.      (Self : not null access Ref; 
  203.       prop : access WaitSetProperty_T); 
  204.    --  <dref>WaitSet_set_property</dref> 
  205.  
  206.    procedure Get_Property 
  207.      (Self : not null access Ref; 
  208.       prop : access WaitSetProperty_T); 
  209.    --  <dref>WaitSet_get_property</dref> 
  210.  
  211. private 
  212.  
  213.    type Ref is new Ada.Finalization.Limited_Controlled with 
  214.       record 
  215.          Impl_Access : DDS.WaitSet_Impl.Ref_Access; 
  216.       end record; 
  217.  
  218.    procedure Free_Impl is new Ada.Unchecked_Deallocation (Ref'Class, Ref_Access); 
  219.    procedure Free (This : in out Ref_Access) renames Free_Impl; 
  220.  
  221. end DDS.WaitSet;