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