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
@@ -419,6 +419,18 @@ module Roby
419
419
 
420
420
  include TaskDisplaySupport
421
421
 
422
+ def self.all_task_relations
423
+ if @all_task_relations
424
+ @all_task_relations
425
+ else
426
+ result = []
427
+ ObjectSpace.each_object(Roby::RelationSpace) do |space|
428
+ result.concat(space.relations) if space.applied.find { |t| t <= Roby::Task }
429
+ end
430
+ @all_task_relations = result
431
+ end
432
+ end
433
+
422
434
  attr_reader :ui, :scene
423
435
 
424
436
  # A [DRbObject, DRbObject] => GraphicsItem mapping of arrows
@@ -510,25 +522,31 @@ module Roby
510
522
  obj
511
523
  end
512
524
 
525
+ # Initializes the display with the data already decoded from the
526
+ # given data stream, and binds this display to the stream.
513
527
  def stream=(data_stream)
514
528
  super
515
529
 
516
530
  # Initialize the display ...
517
531
  decoder.plans.each do |plan|
518
- discovered_tasks(Time.now, plan, plan.known_tasks)
519
- discovered_events(Time.now, plan, plan.free_events)
532
+ added_tasks(Time.now, plan, plan.known_tasks)
533
+ added_events(Time.now, plan, plan.free_events)
520
534
  end
521
535
  display
522
536
  end
523
537
 
524
538
  def [](item); graphics[item] end
539
+
540
+ # Returns a canvas object that represents this relation
525
541
  def task_relation(from, to, rel, info)
526
542
  arrow(from, to, rel, info, TASK_LAYER)
527
543
  end
544
+ # Returns a canvas object that represents this relation
528
545
  def event_relation(form, to, rel, info)
529
546
  arrow(from, to, rel, info, EVENT_LAYER)
530
547
  end
531
548
 
549
+ # Creates or reuses an arrow object to represent the given relation
532
550
  def arrow(from, to, rel, info, base_layer)
533
551
  id = [from, to, rel]
534
552
  unless item = arrows[id]
@@ -589,9 +607,14 @@ module Roby
589
607
  COLORS[current_color]
590
608
  end
591
609
 
610
+ # True if this relation should be displayed
592
611
  def relation_enabled?(relation); @enabled_relations.include?(relation) end
612
+ # True if this relation should be used for layout
613
+ #
614
+ # See also #relation_enabled?, #layout_relation, #ignore_relation
593
615
  def layout_relation?(relation); relation_enabled?(relation) || @layout_relations.include?(relation) end
594
616
 
617
+ # Display this relation
595
618
  def enable_relation(relation)
596
619
  return if relation_enabled?(relation)
597
620
  @enabled_relations << relation
@@ -602,11 +625,17 @@ module Roby
602
625
  end
603
626
  end
604
627
 
628
+ # The set of relations that should be displayed
605
629
  attr_reader :enabled_relations
630
+
631
+ # Use this relation for layout but not for display
632
+ #
633
+ # See also #ignore_relation
606
634
  def layout_relation(relation)
607
635
  disable_relation(relation)
608
636
  @layout_relations << relation
609
637
  end
638
+ # Don't use this relation at all
610
639
  def ignore_relation(relation)
611
640
  disable_relation(relation)
612
641
  @layout_relations.delete(relation)
@@ -756,19 +785,22 @@ module Roby
756
785
  end
757
786
 
758
787
  def clear_integrated
759
- postponed_events.clear
760
- execution_events.clear
761
- @execution_events = execution_events.find_all { |fired, ev| !fired }
788
+ unless keep_signals
789
+ last_propagated_events, @propagated_events = propagated_events, Array.new
790
+ last_execution_events, @execution_events =
791
+ execution_events.partition { |fired, ev| fired }
792
+ end
793
+ !(last_propagated_events.empty? && last_execution_events.empty?)
762
794
  end
763
795
 
796
+ # Update the display with new data that has come from the data
797
+ # stream.
798
+ #
799
+ # It would be too complex at this stage to know if the plan has been
800
+ # updated, so the method always returns true
764
801
  def update
765
802
  return unless decoder
766
803
 
767
- if keep_signals
768
- @execution_events = @last_execution_events.concat(execution_events)
769
- @propagated_events.concat @last_propagated_events
770
- end
771
-
772
804
  update_prefixes_removal
773
805
  clear_flashing_objects
774
806
 
@@ -912,11 +944,7 @@ module Roby
912
944
  end
913
945
  end
914
946
 
915
- @last_propagated_events, @propagated_events = propagated_events, Array.new
916
- @last_execution_events, @execution_events =
917
- execution_events.partition { |fired, ev| fired }
918
-
919
- postponed_events.clear
947
+ true
920
948
  end
921
949
 
922
950
  def remove_graphics(item, scene = nil)
@@ -995,7 +1023,7 @@ module Roby
995
1023
  def removed_event_child(time, parent, rel, child)
996
1024
  remove_graphics(arrows.delete([local_event(parent), local_event(child), rel]))
997
1025
  end
998
- def discovered_tasks(time, plan, tasks)
1026
+ def added_tasks(time, plan, tasks)
999
1027
  tasks.each do |obj|
1000
1028
  obj.flags[:pending] = true if obj.respond_to?(:flags)
1001
1029
  task = local_task(obj)
@@ -47,9 +47,6 @@ module Roby
47
47
  discovered_displays = Array.new
48
48
  @available_servers = Array.new
49
49
 
50
- # Add disable_discovery in the list of finalizers
51
- Control.finalizers << method(:disable_discovery)
52
-
53
50
  @discovery_thread = Thread.new do
54
51
  begin
55
52
  loop do
@@ -75,7 +72,7 @@ module Roby
75
72
 
76
73
  # Stops the discovery thread if it is running
77
74
  def self.disable_discovery
78
- Control.finalizers.delete(method(:disable_discovery))
75
+ Roby.engine.finalizers.delete(method(:disable_discovery))
79
76
  if @discovery_thread
80
77
  @discovery_thread.raise Interrupt, "quitting"
81
78
  @discovery_thread.join
@@ -1,16 +1,16 @@
1
+ require 'set'
2
+
1
3
  module Roby
2
4
  module Log
3
5
  class Timings
4
6
  REF_TIMING = :start
5
7
  ALL_TIMINGS = [ :real_start, :events,
6
8
  :structure_check, :exception_propagation,
7
- :exceptions_fatal, :garbage_collect, :application_errors,
8
- :expected_ruby_gc, :ruby_gc, :droby, :expected_sleep, :sleep, :end ]
9
+ :exceptions_fatal, :garbage_collect,
10
+ :ruby_gc, :expected_sleep, :sleep, :end ]
9
11
 
10
- NUMERIC_FIELDS = [:cycle_index, :live_objects, :object_allocation, :log_queue_size, :ruby_gc_duration,
11
- :plan_task_count, :plan_event_count]
12
- DELTAS = [:cpu_time]
13
- ALL_NUMERIC_FIELDS = NUMERIC_FIELDS + DELTAS
12
+ ALL_NUMERIC_FIELDS = [:cycle_index, :live_objects, :object_allocation, :heap_slots,
13
+ :log_queue_size, :plan_task_count, :plan_event_count, :cpu_time]
14
14
 
15
15
  ALL_FIELDS = ALL_TIMINGS + ALL_NUMERIC_FIELDS + [:event_count, :pos]
16
16
 
@@ -23,7 +23,86 @@ module Roby
23
23
  end
24
24
  def rewind; logfile.rewind end
25
25
 
26
- def each_cycle(cumulative = false)
26
+ # Read the logfile index, extract statistic information from it and
27
+ # yield them cycle-by-cycle. The format of +timings+ is the
28
+ # following:
29
+ #
30
+ # [start, real_start, events,
31
+ # structure_check, exception_propagation,
32
+ # exceptions_fatal, garbage_collect,
33
+ # ruby_gc, expected_sleep, sleep, end]
34
+ #
35
+ # where +start+ is the target start time of the cycle as a Time
36
+ # object. The rest of the values are floating-point values which
37
+ # represent offset from +start+ if +cumulative+ is true or offset
38
+ # from the previous one if +cumulative+ is false. Therefore, in the
39
+ # latter case, the values represent the actual duration of each
40
+ # phase in the execution engine.
41
+ #
42
+ # The phases are as follows:
43
+ # real_start::
44
+ # the actual starting time. It allows to see the offset due (for
45
+ # instance) to the uncertainty in sleep
46
+ # events::
47
+ # event propagation phase, including the propagation of dRoby
48
+ # events (events coming from remote hosts)
49
+ # structure_check::
50
+ # first structure checking pass
51
+ # exception_propagation::
52
+ # exception propagation phase
53
+ # exceptions_fatal::
54
+ # second structure checking pass, and propagation of the fatal
55
+ # errors (i.e. killing the involved tasks)
56
+ # garbage_collect::
57
+ # Roby's garbage collection pass
58
+ # ruby_gc::
59
+ # if GC.enable accepts a true/false argument, Roby will
60
+ # explicitely allow the GC to run only at a specific point, and
61
+ # monitor its execution time. This is the result. Note that Roby
62
+ # issues a warning at startup if it is not the case.
63
+ # expected_sleep::
64
+ # how much time Roby wanted to sleep (i.e. how many milliseconds
65
+ # were given to the sleep() call)
66
+ # sleep::
67
+ # how much time Roby actually slept
68
+ # end::
69
+ # end of the cycle
70
+ #
71
+ # The second array that is yield, +numeric+, contains non-timing
72
+ # statistics. Its format is:
73
+ #
74
+ # [cycle_index, live_objects, object_allocation, log_queue_size,
75
+ # plan_task_count, plan_event_count, cpu_time]
76
+ #
77
+ # where
78
+ #
79
+ # cycle_index::
80
+ # The index of this cycle. Note that some number can be missing: if one
81
+ # cycle takes more than two time its allocated period, then +cycle_index+ is
82
+ # updated to reflect the cycles that have been missed.
83
+ # live_objects::
84
+ # The count of allocated objects at the end of the cycle. It is only valid
85
+ # on Ruby interpreters that have been patched to report this value
86
+ # efficiently.
87
+ # object_allocation::
88
+ # How many objects have been allocated during this cycle. This is valid only
89
+ # if Ruby GC is controlled by Roby (see the description of +ruby_gc+ above).
90
+ # Otherwise, it will be invalid in cycles where the Ruby GC ran, as the
91
+ # statistics can't correct the objects freed by Ruby's GC.
92
+ # log_queue_size::
93
+ # The logger runs in a thread separated from the execution engine, and a
94
+ # fixed-size queue is used to communicate between the threads. This value is
95
+ # the size of the queue at the end of the cycle (after sleep()). It is
96
+ # mainly used for debugging purposes: if this queue is almost full, then the
97
+ # execution engine thread will probably be interrupted to let the log thread
98
+ # empty the queue.
99
+ # plan_task_count::
100
+ # The count of tasks in the plan at the end of the cycle.
101
+ # plan_event_count::
102
+ # The count of free events in the plan at the end of the cycle.
103
+ # cpu_time::
104
+ # The CPU time taken by the Roby controller for this cycle.
105
+ def each_cycle(cumulative = false) # :yield:numeric, timings
27
106
  last_deltas = Hash.new
28
107
  for data in logfile.index_data[1..-1]
29
108
  result = []
@@ -54,18 +133,8 @@ module Roby
54
133
  end
55
134
  end
56
135
 
57
- numeric = data.values_at(*NUMERIC_FIELDS)
58
- deltas = DELTAS.map do |name|
59
- value = if old_value = last_deltas[name]
60
- data[name] - old_value
61
- else
62
- 0
63
- end
64
- last_deltas[name] = data[name]
65
- value
66
- end
67
-
68
- yield(numeric + deltas, result)
136
+ numeric = data.values_at(*ALL_NUMERIC_FIELDS)
137
+ yield(numeric, result)
69
138
  end
70
139
 
71
140
  rescue ArgumentError => e
@@ -1,7 +1,3 @@
1
- require 'roby/relations'
2
- require 'roby/distributed/base'
3
- require 'roby/basic_object'
4
-
5
1
  module Roby
6
2
  # Base class for all objects which are included in a plan.
7
3
  class PlanObject < BasicObject
@@ -10,6 +6,9 @@ module Roby
10
6
  # The plan this object belongs to
11
7
  attr_reader :plan
12
8
 
9
+ # The engine which acts on +plan+ (if there is one)
10
+ def engine; plan.engine end
11
+
13
12
  # The place where this object has been removed from its plan. Once an
14
13
  # object is removed from its plan, it cannot be added back again.
15
14
  attr_accessor :removed_at
@@ -29,6 +28,109 @@ module Roby
29
28
  @plan = new_plan
30
29
  end
31
30
 
31
+ # The propagation engine object for this. For PlanObject instances, it
32
+ # is always the plan itself.
33
+ def propagation_engine
34
+ plan
35
+ end
36
+
37
+ # If +self+ is a transaction proxy, returns the underlying plan object,
38
+ # regardless of how many transactions there is on the stack. Otherwise,
39
+ # return self.
40
+ def real_object
41
+ result = self
42
+ while result.respond_to?(:__getobj__)
43
+ result = result.__getobj__
44
+ end
45
+ result
46
+ end
47
+
48
+ # Returns the stack of transactions/plans this object is part of,
49
+ # starting with self.plan.
50
+ def transaction_stack
51
+ result = [plan]
52
+ obj = self
53
+ while obj.respond_to?(:__getobj__)
54
+ obj = obj.__getobj__
55
+ result << obj.plan
56
+ end
57
+ result
58
+ end
59
+
60
+ # call-seq:
61
+ # merged_relation(:each_child_object, false, Dependency) do |parent, child|
62
+ # end
63
+ # merged_relation(:each_child_object, true, Dependency) do |child|
64
+ # end
65
+ #
66
+ # Behaves like +enumerator+, but merges all the changes that underlying
67
+ # transactions may have applied. I.e. it is equivalent to applying
68
+ # +enumerator+ on the plan that would be the result of the application
69
+ # of the whole transaction stack
70
+ #
71
+ # If +instrusive+ is false, the edges are yielded at the level they
72
+ # appear. I.e. both the parent and the child are given, and [parent,
73
+ # child] may be part of a parent plan of self.plan.
74
+ #
75
+ # If +instrusive+ is true, the related objects are recursively added to
76
+ # all transactions in the transaction stack, and are given at the end.
77
+ # I.e. only the related object is yield, and it is guaranteed to be
78
+ # included in self.plan.
79
+ def merged_relations(enumerator, intrusive, *args, &block)
80
+ if !block_given?
81
+ return enum_for(:merged_relations, enumerator, intrusive, *args)
82
+ end
83
+
84
+ plan_chain = self.transaction_stack
85
+ object = self.real_object
86
+
87
+ pending = Array.new
88
+ while plan_chain.size > 1
89
+ plan = plan_chain.pop
90
+ next_plan = plan_chain.last
91
+
92
+ # Objects that are in +plan+ but not in +next_plan+ are
93
+ # automatically added, as +next_plan+ is not able to change
94
+ # them. Those that are included in +next_plan+ are handled
95
+ # later.
96
+ new_objects = Array.new
97
+ object.send(enumerator, *args) do |related_object, _|
98
+ next if next_plan[related_object, false]
99
+
100
+ if !intrusive
101
+ yield(object, related_object)
102
+ else
103
+ new_objects << related_object
104
+ end
105
+ end
106
+
107
+ # Here, pending contains objects from the previous plan (i.e. in
108
+ # plan.plan). Proxy them in +plan+.
109
+ #
110
+ # It is important to do that *after* we enumerated the relations
111
+ # that exist in +plan+ (above), as it reduces the number of
112
+ # relations at each level.
113
+ pending.map! { |t| plan[t] }
114
+ # And add the new objects that we just discovered
115
+ pending.concat(new_objects)
116
+
117
+ if next_plan
118
+ object = next_plan[object]
119
+ end
120
+ end
121
+
122
+ if intrusive
123
+ send(enumerator, *args, &block)
124
+ for related_object in pending
125
+ yield(self.plan[related_object])
126
+ end
127
+ else
128
+ send(enumerator, *args) do |related_object, _|
129
+ yield(self, related_object)
130
+ end
131
+ end
132
+ end
133
+
32
134
  # A three-state flag with the following values:
33
135
  # nil:: the object is executable if its plan is
34
136
  # true:: the object is executable
@@ -68,9 +170,9 @@ module Roby
68
170
  elsif other.plan && plan
69
171
  raise RuntimeError, "cannot add a relation between two objects from different plans. #{self} is from #{plan} and #{other} is from #{other.plan}"
70
172
  elsif plan
71
- self.plan.discover(other)
173
+ self.plan.add(other)
72
174
  elsif other.plan
73
- other.plan.discover(self)
175
+ other.plan.add(self)
74
176
  end
75
177
  end
76
178
  protected :synchronize_plan
@@ -233,15 +335,37 @@ module Roby
233
335
  end
234
336
  end
235
337
 
236
- # Checks if we have the right to remove a relation. Raises
237
- # OwnershipError if it is not the case
238
- def removing_child_object(child, type)
239
- super if defined? super
338
+ # Hook called when a new child is added to this object in the given
339
+ # relations and with the given information object.
340
+ def adding_child_object(child, relations, info)
341
+ super if defined? super
342
+ return if !plan
343
+
344
+ for trsc in plan.transactions
345
+ next unless trsc.proxying?
346
+ if (parent_proxy = trsc[self, false]) && (child_proxy = trsc[child, false])
347
+ trsc.adding_plan_relation(parent_proxy, child_proxy, relations, info)
348
+ end
349
+ end
350
+ end
240
351
 
352
+ # Hook called when a child of this object is being removed from the
353
+ # given relations.
354
+ def removing_child_object(child, relations)
241
355
  unless read_write? || child.read_write?
242
356
  raise OwnershipError, "cannot remove a relation between two objects we don't own"
243
357
  end
244
- end
358
+
359
+ super if defined? super
360
+ return if !plan
361
+
362
+ for trsc in plan.transactions
363
+ next unless trsc.proxying?
364
+ if (parent_proxy = trsc[self, false]) && (child_proxy = trsc[child, false])
365
+ trsc.removing_plan_relation(parent_proxy, child_proxy, relations)
366
+ end
367
+ end
368
+ end
245
369
  end
246
370
  end
247
371