roby 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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