roby 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. data/History.txt +7 -5
  2. data/Manifest.txt +91 -16
  3. data/README.txt +24 -24
  4. data/Rakefile +92 -64
  5. data/app/config/app.yml +42 -43
  6. data/app/config/init.rb +26 -0
  7. data/benchmark/alloc_misc.rb +123 -0
  8. data/benchmark/discovery_latency.rb +67 -0
  9. data/benchmark/garbage_collection.rb +48 -0
  10. data/benchmark/genom.rb +31 -0
  11. data/benchmark/transactions.rb +62 -0
  12. data/bin/roby +1 -1
  13. data/bin/roby-log +16 -6
  14. data/doc/guide/.gitignore +2 -0
  15. data/doc/guide/config.yaml +34 -0
  16. data/doc/guide/ext/init.rb +14 -0
  17. data/doc/guide/ext/previous_next.rb +40 -0
  18. data/doc/guide/ext/rdoc_links.rb +33 -0
  19. data/doc/guide/index.rdoc +16 -0
  20. data/doc/guide/overview.rdoc +62 -0
  21. data/doc/guide/plan_modifications.rdoc +67 -0
  22. data/doc/guide/src/abstraction/achieve_with.page +8 -0
  23. data/doc/guide/src/abstraction/forwarding.page +8 -0
  24. data/doc/guide/src/abstraction/hierarchy.page +19 -0
  25. data/doc/guide/src/abstraction/index.page +28 -0
  26. data/doc/guide/src/abstraction/task_models.page +13 -0
  27. data/doc/guide/src/basics.template +6 -0
  28. data/doc/guide/src/basics/app.page +139 -0
  29. data/doc/guide/src/basics/code_examples.page +33 -0
  30. data/doc/guide/src/basics/dry.page +69 -0
  31. data/doc/guide/src/basics/errors.page +443 -0
  32. data/doc/guide/src/basics/events.page +179 -0
  33. data/doc/guide/src/basics/hierarchy.page +275 -0
  34. data/doc/guide/src/basics/index.page +11 -0
  35. data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
  36. data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
  37. data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
  38. data/doc/guide/src/basics/log_replay/goForward_4.png +0 -0
  39. data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
  40. data/doc/guide/src/basics/log_replay/hierarchy_error_1.png +0 -0
  41. data/doc/guide/src/basics/log_replay/hierarchy_error_2.png +0 -0
  42. data/doc/guide/src/basics/log_replay/hierarchy_error_3.png +0 -0
  43. data/doc/guide/src/basics/log_replay/plan_repair_1.png +0 -0
  44. data/doc/guide/src/basics/log_replay/plan_repair_2.png +0 -0
  45. data/doc/guide/src/basics/log_replay/plan_repair_3.png +0 -0
  46. data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
  47. data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
  48. data/doc/guide/src/basics/log_replay/roby_log_relation_window.png +0 -0
  49. data/doc/guide/src/basics/log_replay/roby_replay_event_representation.png +0 -0
  50. data/doc/guide/src/basics/plan_objects.page +71 -0
  51. data/doc/guide/src/basics/relations_display.page +203 -0
  52. data/doc/guide/src/basics/roby_cycle_overview.png +0 -0
  53. data/doc/guide/src/basics/shell.page +102 -0
  54. data/doc/guide/src/basics/summary.page +32 -0
  55. data/doc/guide/src/basics/tasks.page +357 -0
  56. data/doc/guide/src/basics_shell_header.txt +16 -0
  57. data/doc/guide/src/cycle/cycle-overview.png +0 -0
  58. data/doc/guide/src/cycle/cycle-overview.svg +208 -0
  59. data/doc/guide/src/cycle/error_handling.page +168 -0
  60. data/doc/guide/src/cycle/error_instantaneous_repair.png +0 -0
  61. data/doc/guide/src/cycle/error_instantaneous_repair.svg +1224 -0
  62. data/doc/guide/src/cycle/garbage_collection.page +10 -0
  63. data/doc/guide/src/cycle/index.page +23 -0
  64. data/doc/guide/src/cycle/propagation.page +154 -0
  65. data/doc/guide/src/cycle/propagation_diamond.png +0 -0
  66. data/doc/guide/src/cycle/propagation_diamond.svg +1279 -0
  67. data/doc/guide/src/default.css +319 -0
  68. data/doc/guide/src/default.template +74 -0
  69. data/doc/guide/src/htmldoc.metainfo +20 -0
  70. data/doc/guide/src/htmldoc.virtual +18 -0
  71. data/doc/guide/src/images/bodybg.png +0 -0
  72. data/doc/guide/src/images/contbg.png +0 -0
  73. data/doc/guide/src/images/footerbg.png +0 -0
  74. data/doc/guide/src/images/gradient1.png +0 -0
  75. data/doc/guide/src/images/gradient2.png +0 -0
  76. data/doc/guide/src/index.page +7 -0
  77. data/doc/guide/src/introduction/index.page +29 -0
  78. data/doc/guide/src/introduction/install.page +133 -0
  79. data/doc/{papers.rdoc → guide/src/introduction/publications.page} +5 -2
  80. data/doc/{videos.rdoc → guide/src/introduction/videos.page} +4 -2
  81. data/doc/guide/src/plugins/fault_tolerance.page +44 -0
  82. data/doc/guide/src/plugins/index.page +11 -0
  83. data/doc/guide/src/plugins/subsystems.page +45 -0
  84. data/doc/guide/src/relations/dependency.page +89 -0
  85. data/doc/guide/src/relations/index.page +12 -0
  86. data/doc/misc/update_github +24 -0
  87. data/doc/tutorials/02-GoForward.rdoc +3 -3
  88. data/ext/graph/graph.cc +46 -0
  89. data/lib/roby.rb +57 -22
  90. data/lib/roby/app.rb +132 -112
  91. data/lib/roby/app/plugins/rake.rb +21 -0
  92. data/lib/roby/app/rake.rb +0 -7
  93. data/lib/roby/app/run.rb +1 -1
  94. data/lib/roby/app/scripts/distributed.rb +1 -2
  95. data/lib/roby/app/scripts/generate/bookmarks.rb +1 -1
  96. data/lib/roby/app/scripts/results.rb +2 -1
  97. data/lib/roby/app/scripts/run.rb +6 -2
  98. data/lib/roby/app/scripts/shell.rb +11 -11
  99. data/lib/roby/config.rb +1 -1
  100. data/lib/roby/decision_control.rb +62 -3
  101. data/lib/roby/distributed.rb +4 -0
  102. data/lib/roby/distributed/base.rb +8 -0
  103. data/lib/roby/distributed/communication.rb +12 -8
  104. data/lib/roby/distributed/connection_space.rb +61 -44
  105. data/lib/roby/distributed/distributed_object.rb +1 -1
  106. data/lib/roby/distributed/notifications.rb +22 -30
  107. data/lib/roby/distributed/peer.rb +13 -8
  108. data/lib/roby/distributed/proxy.rb +5 -5
  109. data/lib/roby/distributed/subscription.rb +4 -4
  110. data/lib/roby/distributed/transaction.rb +3 -3
  111. data/lib/roby/event.rb +176 -110
  112. data/lib/roby/exceptions.rb +12 -4
  113. data/lib/roby/execution_engine.rb +1604 -0
  114. data/lib/roby/external_process_task.rb +225 -0
  115. data/lib/roby/graph.rb +0 -6
  116. data/lib/roby/interface.rb +221 -137
  117. data/lib/roby/log/console.rb +5 -3
  118. data/lib/roby/log/data_stream.rb +94 -16
  119. data/lib/roby/log/dot.rb +8 -8
  120. data/lib/roby/log/event_stream.rb +13 -3
  121. data/lib/roby/log/file.rb +43 -18
  122. data/lib/roby/log/gui/basic_display_ui.rb +89 -0
  123. data/lib/roby/log/gui/chronicle_view_ui.rb +90 -0
  124. data/lib/roby/log/gui/data_displays.rb +4 -5
  125. data/lib/roby/log/gui/data_displays_ui.rb +146 -0
  126. data/lib/roby/log/gui/relations.rb +18 -18
  127. data/lib/roby/log/gui/relations_ui.rb +120 -0
  128. data/lib/roby/log/gui/relations_view_ui.rb +144 -0
  129. data/lib/roby/log/gui/replay.rb +41 -13
  130. data/lib/roby/log/gui/replay_controls.rb +3 -0
  131. data/lib/roby/log/gui/replay_controls.ui +133 -110
  132. data/lib/roby/log/gui/replay_controls_ui.rb +249 -0
  133. data/lib/roby/log/hooks.rb +19 -18
  134. data/lib/roby/log/logger.rb +7 -6
  135. data/lib/roby/log/notifications.rb +4 -4
  136. data/lib/roby/log/plan_rebuilder.rb +20 -22
  137. data/lib/roby/log/relations.rb +44 -16
  138. data/lib/roby/log/server.rb +1 -4
  139. data/lib/roby/log/timings.rb +88 -19
  140. data/lib/roby/plan-object.rb +135 -11
  141. data/lib/roby/plan.rb +408 -224
  142. data/lib/roby/planning/loops.rb +32 -25
  143. data/lib/roby/planning/model.rb +157 -51
  144. data/lib/roby/planning/task.rb +47 -20
  145. data/lib/roby/query.rb +128 -92
  146. data/lib/roby/relations.rb +254 -136
  147. data/lib/roby/relations/conflicts.rb +6 -9
  148. data/lib/roby/relations/dependency.rb +358 -0
  149. data/lib/roby/relations/ensured.rb +0 -1
  150. data/lib/roby/relations/error_handling.rb +0 -1
  151. data/lib/roby/relations/events.rb +0 -2
  152. data/lib/roby/relations/executed_by.rb +26 -11
  153. data/lib/roby/relations/planned_by.rb +14 -14
  154. data/lib/roby/robot.rb +46 -0
  155. data/lib/roby/schedulers/basic.rb +34 -0
  156. data/lib/roby/standalone.rb +4 -0
  157. data/lib/roby/standard_errors.rb +21 -15
  158. data/lib/roby/state/events.rb +5 -4
  159. data/lib/roby/support.rb +107 -6
  160. data/lib/roby/task-operations.rb +23 -19
  161. data/lib/roby/task.rb +522 -148
  162. data/lib/roby/task_index.rb +80 -0
  163. data/lib/roby/test/common.rb +283 -44
  164. data/lib/roby/test/distributed.rb +53 -37
  165. data/lib/roby/test/testcase.rb +9 -204
  166. data/lib/roby/test/tools.rb +3 -3
  167. data/lib/roby/transactions.rb +154 -111
  168. data/lib/roby/transactions/proxy.rb +40 -7
  169. data/manifest.xml +20 -0
  170. data/plugins/fault_injection/README.txt +0 -3
  171. data/plugins/fault_injection/Rakefile +2 -8
  172. data/plugins/fault_injection/app.rb +1 -1
  173. data/plugins/fault_injection/fault_injection.rb +3 -3
  174. data/plugins/fault_injection/test/test_fault_injection.rb +19 -25
  175. data/plugins/subsystems/README.txt +0 -3
  176. data/plugins/subsystems/Rakefile +2 -7
  177. data/plugins/subsystems/app.rb +27 -16
  178. data/plugins/subsystems/test/app/config/init.rb +3 -0
  179. data/plugins/subsystems/test/app/planners/main.rb +1 -1
  180. data/plugins/subsystems/test/app/tasks/services.rb +1 -1
  181. data/plugins/subsystems/test/test_subsystems.rb +23 -16
  182. data/test/distributed/test_communication.rb +32 -15
  183. data/test/distributed/test_connection.rb +28 -26
  184. data/test/distributed/test_execution.rb +59 -54
  185. data/test/distributed/test_mixed_plan.rb +34 -34
  186. data/test/distributed/test_plan_notifications.rb +26 -26
  187. data/test/distributed/test_protocol.rb +57 -48
  188. data/test/distributed/test_query.rb +11 -7
  189. data/test/distributed/test_remote_plan.rb +71 -71
  190. data/test/distributed/test_transaction.rb +50 -47
  191. data/test/mockups/external_process +28 -0
  192. data/test/planning/test_loops.rb +163 -119
  193. data/test/planning/test_model.rb +3 -3
  194. data/test/planning/test_task.rb +27 -7
  195. data/test/relations/test_conflicts.rb +3 -3
  196. data/test/relations/test_dependency.rb +324 -0
  197. data/test/relations/test_ensured.rb +2 -2
  198. data/test/relations/test_executed_by.rb +94 -19
  199. data/test/relations/test_planned_by.rb +11 -9
  200. data/test/suite_core.rb +6 -3
  201. data/test/suite_distributed.rb +1 -0
  202. data/test/suite_planning.rb +1 -0
  203. data/test/suite_relations.rb +2 -2
  204. data/test/tasks/test_external_process.rb +126 -0
  205. data/test/{test_thread_task.rb → tasks/test_thread_task.rb} +17 -20
  206. data/test/test_bgl.rb +21 -1
  207. data/test/test_event.rb +229 -155
  208. data/test/test_exceptions.rb +79 -80
  209. data/test/test_execution_engine.rb +987 -0
  210. data/test/test_gui.rb +1 -1
  211. data/test/test_interface.rb +11 -5
  212. data/test/test_log.rb +18 -7
  213. data/test/test_log_server.rb +1 -0
  214. data/test/test_plan.rb +229 -395
  215. data/test/test_query.rb +193 -35
  216. data/test/test_relations.rb +88 -8
  217. data/test/test_state.rb +55 -37
  218. data/test/test_support.rb +1 -1
  219. data/test/test_task.rb +371 -218
  220. data/test/test_testcase.rb +32 -16
  221. data/test/test_transactions.rb +211 -170
  222. data/test/test_transactions_proxy.rb +37 -19
  223. metadata +169 -71
  224. data/.gitignore +0 -29
  225. data/doc/styles/allison.css +0 -314
  226. data/doc/styles/allison.js +0 -316
  227. data/doc/styles/allison.rb +0 -276
  228. data/doc/styles/jamis.rb +0 -593
  229. data/lib/roby/control.rb +0 -746
  230. data/lib/roby/executives/simple.rb +0 -30
  231. data/lib/roby/propagation.rb +0 -562
  232. data/lib/roby/relations/hierarchy.rb +0 -239
  233. data/lib/roby/transactions/updates.rb +0 -139
  234. data/test/relations/test_hierarchy.rb +0 -158
  235. data/test/test_control.rb +0 -399
  236. data/test/test_propagation.rb +0 -210
@@ -194,7 +194,7 @@ module Roby
194
194
 
195
195
  call(:create_sibling, object)
196
196
  subscriptions << object.sibling_on(self)
197
- Roby::Control.synchronize do
197
+ Roby.synchronize do
198
198
  local_server.subscribe(object)
199
199
  end
200
200
 
@@ -64,9 +64,9 @@ module Roby
64
64
  # Hook called when a new task is marked as mission. It sends a
65
65
  # PeerServer#plan_set_mission message to the remote host.
66
66
  #
67
- # Note that plan will have called the #discovered_tasks hook
67
+ # Note that plan will have called the #added_tasks hook
68
68
  # beforehand
69
- def inserted(task)
69
+ def added_mission(task)
70
70
  super if defined? super
71
71
  return unless task.distribute? && task.self_owned?
72
72
 
@@ -80,7 +80,7 @@ module Roby
80
80
 
81
81
  # Hook called when a new task is not a mission anymore. It sends a
82
82
  # PeerServer#plan_set_mission message to the remote host.
83
- def discarded(task)
83
+ def unmarked_mission(task)
84
84
  super if defined? super
85
85
  return unless task.distribute? && task.self_owned?
86
86
 
@@ -91,10 +91,10 @@ module Roby
91
91
  end
92
92
  end
93
93
 
94
- # Common implementation for the #discovered_events and
95
- # #discovered_tasks hooks. It sends PeerServer#plan_discover for
94
+ # Common implementation for the #added_events and
95
+ # #added_tasks hooks. It sends PeerServer#plan_add for
96
96
  # all tasks which can be shared among plan managers
97
- def self.discovered_objects(plan, objects)
97
+ def self.added_objects(plan, objects)
98
98
  unless Distributed.updating?(plan)
99
99
  relations = nil
100
100
  Distributed.each_updated_peer(plan) do |peer|
@@ -105,24 +105,24 @@ module Roby
105
105
  return if objects.empty?
106
106
  relations = Distributed.subgraph_of(objects)
107
107
  end
108
- peer.transmit(:plan_discover, plan, objects, relations)
108
+ peer.transmit(:plan_add, plan, objects, relations)
109
109
  end
110
110
  Distributed.trigger(*objects)
111
111
  end
112
112
  end
113
- # New tasks have been discovered in the plan.
113
+ # New tasks have been added in the plan.
114
114
  #
115
- # See PlanModificationHooks.discovered_objects
116
- def discovered_tasks(tasks)
115
+ # See PlanModificationHooks.added_objects
116
+ def added_tasks(tasks)
117
117
  super if defined? super
118
- PlanModificationHooks.discovered_objects(self, tasks)
118
+ PlanModificationHooks.added_objects(self, tasks)
119
119
  end
120
- # New free events have been discovered in the plan.
120
+ # New free events have been added in the plan.
121
121
  #
122
- # See PlanModificationHooks.discovered_objects
123
- def discovered_events(events)
122
+ # See PlanModificationHooks.added_objects
123
+ def added_events(events)
124
124
  super if defined? super
125
- PlanModificationHooks.discovered_objects(self, events)
125
+ PlanModificationHooks.added_objects(self, events)
126
126
  end
127
127
 
128
128
  # Hook called when +from+ has been replaced by +to+ in the plan.
@@ -190,9 +190,9 @@ module Roby
190
190
  task = peer.local_object(task)
191
191
  if plan.owns?(task)
192
192
  if flag
193
- plan.insert(task)
193
+ plan.add_mission(task)
194
194
  else
195
- plan.discard(task)
195
+ plan.remove_mission(task)
196
196
  end
197
197
  else
198
198
  task.mission = flag
@@ -201,14 +201,14 @@ module Roby
201
201
  end
202
202
 
203
203
  # Message received when the set of tasks +m_tasks+ has been
204
- # discovered by the remote plan. +m_relations+ describes the
204
+ # added by the remote plan. +m_relations+ describes the
205
205
  # internal relations between elements of +m_tasks+. It is in a
206
206
  # format suitable for PeerServer#set_relations.
207
- def plan_discover(plan, m_tasks, m_relations)
207
+ def plan_add(plan, m_tasks, m_relations)
208
208
  Distributed.update(plan = peer.local_object(plan)) do
209
209
  tasks = peer.local_object(m_tasks).to_value_set
210
210
  Distributed.update_all(tasks) do
211
- plan.discover(tasks)
211
+ plan.add(tasks)
212
212
  m_relations.each_slice(2) do |obj, rel|
213
213
  set_relations(obj, rel)
214
214
  end
@@ -429,7 +429,7 @@ module Roby
429
429
 
430
430
  event = event_for(from_generator, event_id, time, context)
431
431
 
432
- event.send(:propagation_id=, Propagation.propagation_id)
432
+ event.send(:propagation_id=, from_generator.plan.engine.propagation_id)
433
433
  from_generator.instance_variable_set("@happened", true)
434
434
  from_generator.fired(event)
435
435
  from_generator.call_handlers(event)
@@ -450,7 +450,7 @@ module Roby
450
450
 
451
451
  # Only add the signalling if we own +to+
452
452
  if to_generator.self_owned?
453
- Propagation.add_event_propagation(only_forward, [event], to_generator, event.context, nil)
453
+ to_generator.plan.engine.add_event_propagation(only_forward, [event], to_generator, event.context, nil)
454
454
  else
455
455
  # Call #signalling or #forwarding to make
456
456
  # +from_generator+ look like as if the event was really
@@ -527,13 +527,5 @@ module Roby
527
527
  nil
528
528
  end
529
529
  end
530
-
531
- Roby::Control.at_cycle_end do
532
- peers.each_value do |peer|
533
- if peer.connected?
534
- peer.transmit(:state_update, Roby::State)
535
- end
536
- end
537
- end
538
530
  end
539
531
  end
@@ -10,7 +10,7 @@ require 'roby/distributed/proxy'
10
10
  require 'roby/distributed/communication'
11
11
 
12
12
  module Roby
13
- class Control; include DRbUndumped end
13
+ class ExecutionEngine; include DRbUndumped end
14
14
  end
15
15
 
16
16
  module Roby::Distributed
@@ -149,7 +149,7 @@ module Roby::Distributed
149
149
  # +matcher+ changes
150
150
  def add_trigger(id, matcher)
151
151
  triggers[id] = [matcher, (triggered = ValueSet.new)]
152
- Roby.info "#{remote_name} wants notification on #{matcher} (#{id})"
152
+ Roby::Distributed.info "#{remote_name} wants notification on #{matcher} (#{id})"
153
153
 
154
154
  peer.queueing do
155
155
  matcher.each(plan) do |task|
@@ -164,7 +164,7 @@ module Roby::Distributed
164
164
 
165
165
  # Remove the trigger +id+ defined by this peer
166
166
  def remove_trigger(id)
167
- Roby.info "#{remote_name} removed #{id} notification"
167
+ Roby::Distributed.info "#{remote_name} removed #{id} notification"
168
168
  triggers.delete(id)
169
169
  nil
170
170
  end
@@ -276,6 +276,11 @@ module Roby::Distributed
276
276
  # The remote state
277
277
  attr_accessor :state
278
278
 
279
+ # The plan associated to our connection space
280
+ def plan; connection_space.plan end
281
+ # The execution engine associated to #plan
282
+ def engine; connection_space.plan.engine end
283
+
279
284
  # Creates a Peer object for the peer connected at +socket+. This peer
280
285
  # is to be managed by +connection_space+ If a block is given, it is
281
286
  # called in the control thread when the connection is finalized
@@ -310,8 +315,8 @@ module Roby::Distributed
310
315
  local_server.state_update remote_state
311
316
 
312
317
  @task = ConnectionTask.new :peer => self
313
- Roby::Control.once do
314
- connection_space.plan.permanent(task)
318
+ connection_space.plan.engine.once do
319
+ connection_space.plan.add_permanent(task)
315
320
  task.start!
316
321
  task.emit(:ready)
317
322
  end
@@ -362,7 +367,7 @@ module Roby::Distributed
362
367
  end
363
368
 
364
369
  ensure
365
- Roby::Control.synchronize do
370
+ Roby.synchronize do
366
371
  if result_set
367
372
  result_set.each do |task|
368
373
  Roby::Distributed.keep.deref(task)
@@ -407,7 +412,7 @@ module Roby::Distributed
407
412
  trigger.last.call(task)
408
413
  end
409
414
  rescue Exception
410
- Roby.warn "trigger handler #{trigger.last} failed with #{$!.full_message}"
415
+ Roby::Distributed.warn "trigger handler #{trigger.last} failed with #{$!.full_message}"
411
416
  ensure
412
417
  Roby::Distributed.keep.deref(task)
413
418
  end
@@ -539,7 +544,7 @@ module Roby::Distributed
539
544
 
540
545
  yield(local_object(remote_object(object)))
541
546
 
542
- Roby::Control.synchronize do
547
+ Roby.synchronize do
543
548
  objects.each { |obj| Roby::Distributed.keep.deref(obj) }
544
549
  end
545
550
  end
@@ -83,7 +83,7 @@ module Roby
83
83
  plan = peer.local_object(self.plan)
84
84
  return if proxy.plan == plan
85
85
  Distributed.update_all([plan, proxy]) do
86
- plan.discover(proxy)
86
+ plan.add(proxy)
87
87
  end
88
88
  end
89
89
  end
@@ -218,7 +218,7 @@ module Roby
218
218
  def droby_dump(dest)
219
219
  DRoby.new(remote_siblings.droby_dump(dest), owners.droby_dump(dest),
220
220
  model.droby_dump(dest), plan.droby_dump(dest),
221
- Distributed.format(arguments, dest), Distributed.format(data, dest),
221
+ Distributed.format(meaningful_arguments, dest), Distributed.format(data, dest),
222
222
  :mission => mission?, :started => started?,
223
223
  :finished => finished?, :success => success?)
224
224
  end
@@ -271,12 +271,12 @@ module Roby
271
271
  task.success = flags[:success]
272
272
 
273
273
  if task.mission? != flags[:mission]
274
- plan = peer.local_object(self.plan) || Roby.plan
274
+ plan = peer.local_object(self.plan) || peer.connection_space.plan
275
275
  if plan.owns?(task)
276
276
  if flags[:mission]
277
- plan.insert(task)
277
+ plan.add_mission(task)
278
278
  else
279
- plan.discard(task)
279
+ plan.remove_mission(task)
280
280
  end
281
281
  else
282
282
  task.mission = flags[:mission]
@@ -39,14 +39,14 @@ module Roby
39
39
 
40
40
  # The peer wants to subscribe to our main plan
41
41
  def subscribe_plan(sibling)
42
- added_sibling(Roby.plan.remote_id, sibling)
43
- peer.transmit(:subscribed_plan, Roby.plan.remote_id)
44
- subscribe(Roby.plan)
42
+ added_sibling(peer.connection_space.plan.remote_id, sibling)
43
+ peer.transmit(:subscribed_plan, peer.connection_space.plan.remote_id)
44
+ subscribe(peer.connection_space.plan)
45
45
  end
46
46
 
47
47
  # Called by our peer because it has subscribed us to its main plan
48
48
  def subscribed_plan(remote_plan_id)
49
- peer.proxies[remote_plan_id] = Roby.plan
49
+ peer.proxies[remote_plan_id] = peer.connection_space.plan
50
50
  peer.remote_plan = remote_plan_id
51
51
  end
52
52
 
@@ -133,7 +133,7 @@ module Roby
133
133
  end
134
134
  end
135
135
 
136
- def discover(objects) # :nodoc:
136
+ def add(objects) # :nodoc:
137
137
  if objects
138
138
  events, tasks = partition_event_task(objects)
139
139
  for object in (events || []) + (tasks || [])
@@ -360,8 +360,8 @@ module Roby
360
360
  begin
361
361
  Distributed.transaction_handler[trsc] if Distributed.transaction_handler
362
362
  rescue
363
- Roby.warn "transaction handler for #{trsc} failed"
364
- Roby.warn $!.full_message
363
+ Roby::Distributed.warn "transaction handler for #{trsc} failed"
364
+ Roby::Distributed.warn $!.full_message
365
365
  trsc.invalidate("failed transaction handler")
366
366
  end
367
367
  end
@@ -1,8 +1,3 @@
1
- require 'utilrb/weakref'
2
- require 'roby/plan-object'
3
- require 'roby/exceptions'
4
- require 'set'
5
-
6
1
  module Roby
7
2
  # Event objects are the objects representing a particular emission in the
8
3
  # event propagation process. They represent the common propagation
@@ -22,7 +17,7 @@ module Roby
22
17
  attr_accessor :propagation_id, :context, :time
23
18
  protected :propagation_id=, :context=, :time=
24
19
 
25
- # The events whose emission triggered this event during the
20
+ # The events whose emission directly triggered this event during the
26
21
  # propagation. The events in this set are subject to Ruby's own
27
22
  # garbage collection, which means that if a source event is garbage
28
23
  # collected (i.e. if all references to the associated task/event
@@ -108,12 +103,6 @@ module Roby
108
103
  # * #forwarding
109
104
  #
110
105
  class EventGenerator < PlanObject
111
- attr_writer :executable
112
-
113
- # True if this event is executable. A non-executable event cannot be
114
- # called even if it is controlable
115
- def executable?; @executable end
116
-
117
106
  # Creates a new Event generator which is emitted as soon as one of this
118
107
  # object and +generator+ is emitted
119
108
  def |(generator)
@@ -127,6 +116,7 @@ module Roby
127
116
  end
128
117
 
129
118
  attr_enumerable(:handler, :handlers) { Array.new }
119
+ attr_enumerable(:once_handler, :once_handlers) { Array.new }
130
120
 
131
121
  def initialize_copy(old) # :nodoc:
132
122
  super
@@ -170,7 +160,6 @@ module Roby
170
160
  end
171
161
  end
172
162
  super() if defined? super
173
- @executable = true
174
163
 
175
164
  end
176
165
 
@@ -187,13 +176,15 @@ module Roby
187
176
  # Checks that the event can be called. Raises various exception
188
177
  # when it is not the case.
189
178
  def check_call_validity
190
- if !self_owned?
191
- raise OwnershipError, "not owner"
179
+ if !plan
180
+ raise EventNotExecutable.new(self), "#emit called on #{self} which is in no plan"
181
+ elsif !engine
182
+ raise EventNotExecutable.new(self), "#emit called on #{self} which is has no associated execution engine"
183
+ elsif !engine.allow_propagation?
184
+ raise PhaseMismatch, "call to #emit is not allowed in this context"
192
185
  elsif !controlable?
193
186
  raise EventNotControlable.new(self), "#call called on a non-controlable event"
194
- elsif !executable?
195
- raise EventNotExecutable.new(self), "#call called on #{self} which is non-executable event"
196
- elsif !Roby.inside_control?
187
+ elsif !engine.inside_control?
197
188
  raise ThreadMismatch, "#call called while not in control thread"
198
189
  end
199
190
  end
@@ -202,21 +193,22 @@ module Roby
202
193
  # when it is not the case.
203
194
  def check_emission_validity
204
195
  if !executable?
205
- raise EventNotExecutable.new(self), "#emit called on #{self} which is not executable"
206
- elsif !self_owned?
207
- raise OwnershipError, "cannot emit an event we don't own. #{self} is owned by #{owners}"
208
- elsif !Roby.inside_control?
196
+ raise EventNotExecutable.new(self), "#emit called on #{self} which is a non-executable event"
197
+ elsif !engine.allow_propagation?
198
+ raise PhaseMismatch, "call to #emit is not allowed in this context"
199
+ elsif !engine.inside_control?
209
200
  raise ThreadMismatch, "#emit called while not in control thread"
210
201
  end
211
202
  end
212
203
 
213
204
  # Returns true if the command has been called and false otherwise
214
205
  # The command won't be called if #postpone() is called within the
215
- # #calling hook
206
+ # #calling hook, in which case the method returns false.
216
207
  #
217
208
  # This is used by propagation code, and should never be called directly
218
- def call_without_propagation(context) # :nodoc:
209
+ def call_without_propagation(context)
219
210
  check_call_validity
211
+
220
212
  if !controlable?
221
213
  raise EventNotControlable.new(self), "#call called on a non-controlable event"
222
214
  end
@@ -225,7 +217,11 @@ module Roby
225
217
  calling(context)
226
218
  @pending = true
227
219
 
228
- Propagation.propagation_context([self]) do
220
+ if !executable?
221
+ raise EventNotExecutable.new(self), "#call called on #{self} which is a non-executable event"
222
+ end
223
+
224
+ plan.engine.propagation_context([self]) do
229
225
  command[context]
230
226
  end
231
227
 
@@ -252,36 +248,46 @@ module Roby
252
248
  def call(*context)
253
249
  check_call_validity
254
250
 
251
+ # This test must not be done in #emit_without_propagation as the
252
+ # other ones: it is possible, using Distributed.update, to disable
253
+ # ownership tests, but that does not work if the test is in
254
+ # #emit_without_propagation
255
+ if !self_owned?
256
+ raise OwnershipError, "not owner"
257
+ end
258
+
255
259
  context.compact!
256
- if Propagation.gathering?
257
- Propagation.add_event_propagation(false, Propagation.sources, self, (context unless context.empty?), nil)
258
- else
259
- Roby::Control.synchronize do
260
- errors = Propagation.propagate_events do |initial_set|
261
- Propagation.add_event_propagation(false, nil, self, (context unless context.empty?), nil)
260
+ engine = plan.engine
261
+ if engine.gathering?
262
+ engine.add_event_propagation(false, engine.propagation_sources, self, (context unless context.empty?), nil)
263
+ else
264
+ Roby.synchronize do
265
+ errors = engine.propagate_events do |initial_set|
266
+ engine.add_event_propagation(false, nil, self, (context unless context.empty?), nil)
262
267
  end
263
268
  if errors.size == 1
264
269
  e = errors.first.exception
265
- raise e, e.message, e.backtrace
270
+ raise e.dup, e.message, Roby.filter_backtrace(e.backtrace)
266
271
  elsif !errors.empty?
267
272
  for e in errors
268
- STDERR.puts e.exception.full_message
273
+ pp e.exception
269
274
  end
275
+ raise "multiple exceptions"
270
276
  end
271
277
  end
272
278
  end
273
279
  end
274
280
 
275
- # Establishes signalling and/or event handlers from this event
276
- # generator.
281
+ # call-seq:
282
+ # on { |event| ... }
277
283
  #
278
- # If +time+ is given it is either a :delay => time association, or a
279
- # :at => time association. In the first case, +time+ is a floating-point
280
- # delay in seconds and in the second case it is a Time object which is
281
- # the absolute point in time at which this propagation must happen.
284
+ # Adds an event handler on this generator. The block gets an Event
285
+ # object which describes the parameters of the emission (context value,
286
+ # time, ...). See Event for details.
282
287
  def on(signal = nil, time = nil, &handler)
283
288
  if signal
284
- self.signal(signal, time)
289
+ Roby.warn_deprecated "EventGenerator#on only accepts event handlers now. Use #signals to establish signalling"
290
+ self.signals(signal, time)
285
291
  end
286
292
 
287
293
  if handler
@@ -299,14 +305,19 @@ module Roby
299
305
  # :at => time association. In the first case, +time+ is a floating-point
300
306
  # delay in seconds and in the second case it is a Time object which is
301
307
  # the absolute point in time at which this propagation must happen.
302
- def signal(generator, timespec = nil)
308
+ def signals(generator, timespec = nil)
303
309
  if !generator.controlable?
304
- raise EventNotControlable.new(self), "trying to establish a signal between #{self} and #{generator}"
310
+ raise EventNotControlable.new(self), "trying to establish a signal from #{self} to #{generator} which is not controllable"
305
311
  end
306
- timespec = Propagation.validate_timespec(timespec)
312
+ timespec = ExecutionEngine.validate_timespec(timespec)
307
313
 
308
314
  add_signal generator, timespec
309
315
  self
316
+ end
317
+
318
+ def signal(generator, timespec = nil)
319
+ Roby.warn_deprecated "EventGenerator#signal has been renamed into EventGenerator#signals"
320
+ signals(generator, timespec)
310
321
  end
311
322
 
312
323
  # A set of blocks called when this event cannot be emitted again
@@ -338,6 +349,11 @@ module Roby
338
349
  @unreachable_event
339
350
  end
340
351
 
352
+ def forward(generator, timespec = nil)
353
+ Roby.warn_deprecated "EventGenerator#forward has been renamed into EventGenerator#forward_to"
354
+ forward_to(generator, timespec)
355
+ end
356
+
341
357
  # Emit +generator+ when +self+ is fired, without calling the command of
342
358
  # +generator+, if any.
343
359
  #
@@ -345,44 +361,57 @@ module Roby
345
361
  # :at => time association. In the first case, +time+ is a floating-point
346
362
  # delay in seconds and in the second case it is a Time object which is
347
363
  # the absolute point in time at which this propagation must happen.
348
- def forward(generator, timespec = nil)
349
- timespec = Propagation.validate_timespec(timespec)
364
+ def forward_to(generator, timespec = nil)
365
+ timespec = ExecutionEngine.validate_timespec(timespec)
350
366
  add_forwarding generator, timespec
351
367
  self
352
- end
368
+ end
353
369
 
354
370
  # Returns an event which is emitted +seconds+ seconds after this one
355
371
  def delay(seconds)
356
372
  if seconds == 0 then self
357
373
  else
358
374
  ev = EventGenerator.new
359
- forward(ev, :delay => seconds)
375
+ forward_to(ev, :delay => seconds)
360
376
  ev
361
377
  end
362
378
  end
363
379
 
364
- # Signal the +signal+ event the first time this event is emitted. If
365
- # +time+ is non-nil, delay the signalling this many seconds.
366
- def signal_once(signal, time = nil); once(signal, time) end
367
-
368
- # Equivalent to #on, but call the handler and/or signal the target
369
- # event only once.
370
- def once(signal = nil, time = nil)
371
- handler = nil
372
- on(signal, time) do |context|
373
- yield(context) if block_given?
374
- self.handlers.delete(handler)
375
- remove_signal(signal) if signal
380
+ # Signals the given target event only once
381
+ def signals_once(signal, delay = nil)
382
+ signals(signal, delay)
383
+ once do |context|
384
+ remove_signal signal
376
385
  end
377
- handler = self.handlers.last
386
+ self
387
+ end
388
+
389
+ # call-seq:
390
+ # once { |context| ... }
391
+ #
392
+ # Calls the provided event handler only once
393
+ def once(signal = nil, time = nil, &block)
394
+ if signal
395
+ Roby.warn_deprecated "the once(event_name) form has been replaced by #signal_once"
396
+ signal_once(signal, time)
397
+ end
398
+
399
+ once_handlers << block
400
+ self
378
401
  end
379
402
 
380
- # Forwards to +ev+ only once
381
- def forward_once(ev)
382
- forward(ev)
383
- once do
403
+ def forward_once(ev, delay = nil)
404
+ Roby.warn_deprecated "#forward_once has been renamed into #forward_to_once"
405
+ forward_to_once(ev)
406
+ end
407
+
408
+ # Forwards to the given target event only once
409
+ def forward_to_once(ev, delay = nil)
410
+ forward_to(ev, delay)
411
+ once do |context|
384
412
  remove_forwarding ev
385
413
  end
414
+ self
386
415
  end
387
416
 
388
417
  def to_event; self end
@@ -401,7 +430,7 @@ module Roby
401
430
  end
402
431
 
403
432
  # Create a new event object for +context+
404
- def new(context); Event.new(self, Propagation.propagation_id, context, Time.now) end
433
+ def new(context); Event.new(self, plan.engine.propagation_id, context, Time.now) end
405
434
 
406
435
  # Adds a propagation originating from this event to event propagation
407
436
  def add_propagation(only_forward, event, signalled, context, timespec) # :nodoc:
@@ -411,7 +440,7 @@ module Roby
411
440
  raise PropagationError, "trying to signal #{signalled} from #{self}"
412
441
  end
413
442
 
414
- Propagation.add_event_propagation(only_forward, [event], signalled, context, timespec)
443
+ plan.engine.add_event_propagation(only_forward, [event], signalled, context, timespec)
415
444
  end
416
445
  private :add_propagation
417
446
 
@@ -420,7 +449,7 @@ module Roby
420
449
  #
421
450
  # This method is always called in a propagation context
422
451
  def fire(event)
423
- Propagation.propagation_context([event]) do |result|
452
+ plan.engine.propagation_context([event]) do |result|
424
453
  each_signal do |signalled|
425
454
  add_propagation(false, event, signalled, event.context, self[signalled, EventStructure::Signal])
426
455
  end
@@ -446,9 +475,17 @@ module Roby
446
475
  begin
447
476
  h.call(event)
448
477
  rescue Exception => e
449
- Propagation.add_error( EventHandlerError.new(e, event) )
478
+ plan.engine.add_error( EventHandlerError.new(e, event) )
450
479
  end
451
480
  end
481
+ each_once_handler do |h|
482
+ begin
483
+ h.call(event)
484
+ rescue Exception => e
485
+ plan.engine_add_error( EventHandlerError.new(e, event) )
486
+ end
487
+ end
488
+ once_handlers.clear
452
489
  end
453
490
 
454
491
  # Raises an exception object when an event whose command has been
@@ -457,30 +494,41 @@ module Roby
457
494
  what, message = *what
458
495
  what ||= EmissionFailed
459
496
 
460
- if !message && what.respond_to?(:to_str)
497
+ if !message && !(what.kind_of?(Class) || what.kind_of?(Exception))
461
498
  message = what.to_str
462
499
  what = EmissionFailed
463
500
  end
464
501
 
465
- failure_message = "failed to emit #{self}: #{message}"
502
+ failure_message =
503
+ if message then "failed to emit #{self}: #{message}"
504
+ elsif what.respond_to?(:message) then "failed to emit #{self}: #{what.message}"
505
+ else "failed to emit #{self}: #{message}"
506
+ end
507
+
466
508
  error = if Class === what then what.new(nil, self)
467
509
  else what
468
510
  end
469
- error = error.exception failure_message
470
511
 
471
- Propagation.add_error(error)
512
+ new_error = error.exception failure_message
513
+ new_error.set_backtrace error.backtrace
514
+ error = new_error
472
515
 
516
+ if !error.kind_of?(LocalizedError)
517
+ error = EmissionFailed.new(error, self)
518
+ end
519
+
520
+ plan.engine.add_error(error)
473
521
  ensure
474
522
  @pending = false
475
523
  end
476
524
 
477
525
  # Emits the event regardless of wether we are in a propagation context
478
- # or not Returns true to match the behavior of
479
- # #call_without_propagation
526
+ # or not. Returns true to match the behavior of #call_without_propagation
480
527
  #
481
528
  # This is used by event propagation. Do not call directly: use #call instead
482
- def emit_without_propagation(context) # :nodoc:
529
+ def emit_without_propagation(context)
483
530
  check_emission_validity
531
+
484
532
  if !executable?
485
533
  raise EventNotExecutable.new(self), "#emit called on #{self} which is not executable"
486
534
  end
@@ -492,7 +540,7 @@ module Roby
492
540
  unless event.respond_to?(:context)
493
541
  raise TypeError, "#{event} is not a valid event object in #{self}"
494
542
  end
495
- event.sources = Propagation.source_events
543
+ event.sources = plan.engine.propagation_source_events
496
544
  fire(event)
497
545
 
498
546
  true
@@ -505,21 +553,31 @@ module Roby
505
553
  def emit(*context)
506
554
  check_emission_validity
507
555
 
556
+ # This test must not be done in #emit_without_propagation as the
557
+ # other ones: it is possible, using Distributed.update, to disable
558
+ # ownership tests, but that does not work if the test is in
559
+ # #emit_without_propagation
560
+ if !self_owned?
561
+ raise OwnershipError, "cannot emit an event we don't own. #{self} is owned by #{owners}"
562
+ end
563
+
508
564
  context.compact!
509
- if Propagation.gathering?
510
- Propagation.add_event_propagation(true, Propagation.sources, self, (context unless context.empty?), nil)
511
- else
512
- Roby::Control.synchronize do
513
- errors = Propagation.propagate_events do |initial_set|
514
- Propagation.add_event_propagation(true, Propagation.sources, self, (context unless context.empty?), nil)
565
+ engine = plan.engine
566
+ if engine.gathering?
567
+ engine.add_event_propagation(true, engine.propagation_sources, self, (context unless context.empty?), nil)
568
+ else
569
+ Roby.synchronize do
570
+ errors = engine.propagate_events do |initial_set|
571
+ engine.add_event_propagation(true, engine.propagation_sources, self, (context unless context.empty?), nil)
515
572
  end
516
573
  if errors.size == 1
517
574
  e = errors.first.exception
518
- raise e, e.message, e.backtrace
575
+ raise e.dup, e.message, Roby.filter_backtrace(e.backtrace)
519
576
  elsif !errors.empty?
520
- for e in errors
521
- STDERR.puts e.full_message
522
- end
577
+ for e in errors
578
+ pp e.exception
579
+ end
580
+ raise "multiple exceptions"
523
581
  end
524
582
  end
525
583
  end
@@ -528,8 +586,9 @@ module Roby
528
586
  # Deprecated. Instead of using
529
587
  # dest.emit_on(source)
530
588
  # now use
531
- # source.forward(dest)
589
+ # source.forward_to(dest)
532
590
  def emit_on(generator, timespec = nil)
591
+ Roby.warn_deprecated "a.emit_on(b) has been replaced by b.forward_to(a)"
533
592
  generator.forward(self, timespec)
534
593
  self
535
594
  end
@@ -558,15 +617,11 @@ module Roby
558
617
  self.emit(yield(context))
559
618
  end
560
619
  else
561
- ev.forward_once self
620
+ ev.forward_to_once self
562
621
  end
563
622
 
564
623
  ev.if_unreachable(true) do |reason|
565
- msg = "#{ev} is unreachable#{ " (#{reason})" if reason }, in #{stack.first}"
566
- if ev.respond_to?(:task)
567
- msg << "\n " << ev.task.history.map { |ev| "#{ev.time.to_hms} #{ev.symbol}: #{ev.context}" }.join("\n ")
568
- end
569
- emit_failed(UnreachableEvent.new(self, reason), msg)
624
+ emit_failed(UnreachableEvent.new(self, reason))
570
625
  end
571
626
  end
572
627
  # For backwards compatibility. Use #achieve_with.
@@ -597,7 +652,7 @@ module Roby
597
652
  #
598
653
  # A reason string can be provided for debugging purposes
599
654
  def postpone(generator, reason = nil)
600
- generator.on self
655
+ generator.signals self
601
656
  yield if block_given?
602
657
  throw :postponed, [generator, reason]
603
658
  end
@@ -673,7 +728,7 @@ module Roby
673
728
  # by the given block
674
729
  def filter(*new_context, &block)
675
730
  filter = FilterGenerator.new(new_context, &block)
676
- self.on(filter)
731
+ self.signals(filter)
677
732
  filter
678
733
  end
679
734
 
@@ -682,7 +737,7 @@ module Roby
682
737
  #
683
738
  # source, ev, limit = (1..3).map { EventGenerator.new(true) }
684
739
  # ev.until(limit).on { STDERR.puts "FIRED !!!" }
685
- # source.on ev
740
+ # source.signals ev
686
741
  #
687
742
  # Will do
688
743
  #
@@ -702,6 +757,19 @@ module Roby
702
757
  super
703
758
  end
704
759
 
760
+ def added_child_object(child, relations, info) # :nodoc:
761
+ super if defined? super
762
+ if relations.include?(Roby::EventStructure::Precedence) && plan && plan.engine
763
+ plan.engine.event_ordering.clear
764
+ end
765
+ end
766
+ def removed_child_object(child, relations) # :nodoc:
767
+ super if defined? super
768
+ if relations.include?(Roby::EventStructure::Precedence) && plan && plan.engine
769
+ plan.engine.event_ordering.clear
770
+ end
771
+ end
772
+
705
773
  @@event_gathering = Hash.new { |h, k| h[k] = ValueSet.new }
706
774
  # If a generator in +events+ fires, add the fired event in +collection+
707
775
  def self.gather_events(collection, events)
@@ -721,30 +789,28 @@ module Roby
721
789
  # event generators +collection+ is listening for.
722
790
  def self.event_gathering; @@event_gathering end
723
791
 
724
- # This module is hooked in Roby::Plan to remove from the
725
- # event_gathering sets the events that have been finalized
726
- module FinalizedEventHook
727
- def finalized_event(event)
728
- super if defined? super
729
- event.unreachable!
730
- end
731
- end
732
- Roby::Plan.include FinalizedEventHook
733
-
734
792
  attr_predicate :unreachable?
793
+ # If the event became unreachable, this holds the reason for its
794
+ # unreachability, if that reason is known. This reason is always an
795
+ # Event instance which represents the emission that triggered this
796
+ # unreachability.
797
+ attr_reader :unreachability_reason
735
798
 
736
799
  # Called internally when the event becomes unreachable
737
- def unreachable!(reason = nil)
800
+ def unreachable!(reason = nil, plan = self.plan)
738
801
  return if @unreachable
739
802
  @unreachable = true
803
+ @unreachability_reason = reason
740
804
 
741
805
  EventGenerator.event_gathering.delete(self)
742
806
 
743
807
  unreachable_handlers.each do |_, block|
744
808
  begin
745
809
  block.call(reason)
810
+ rescue LocalizedError => e
811
+ plan.engine.add_error(e)
746
812
  rescue Exception => e
747
- Propagation.add_error(EventHandlerError.new(e, self))
813
+ plan.engine.add_error(EventHandlerError.new(e, self))
748
814
  end
749
815
  end
750
816
  unreachable_handlers.clear
@@ -935,8 +1001,8 @@ module Roby
935
1001
  end
936
1002
 
937
1003
  if source && limit
938
- source.forward(self)
939
- limit.signal(self)
1004
+ source.forward_to(self)
1005
+ limit.signals(self)
940
1006
  end
941
1007
  end
942
1008
  end