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.
- data/History.txt +7 -5
- data/Manifest.txt +91 -16
- data/README.txt +24 -24
- data/Rakefile +92 -64
- data/app/config/app.yml +42 -43
- data/app/config/init.rb +26 -0
- data/benchmark/alloc_misc.rb +123 -0
- data/benchmark/discovery_latency.rb +67 -0
- data/benchmark/garbage_collection.rb +48 -0
- data/benchmark/genom.rb +31 -0
- data/benchmark/transactions.rb +62 -0
- data/bin/roby +1 -1
- data/bin/roby-log +16 -6
- data/doc/guide/.gitignore +2 -0
- data/doc/guide/config.yaml +34 -0
- data/doc/guide/ext/init.rb +14 -0
- data/doc/guide/ext/previous_next.rb +40 -0
- data/doc/guide/ext/rdoc_links.rb +33 -0
- data/doc/guide/index.rdoc +16 -0
- data/doc/guide/overview.rdoc +62 -0
- data/doc/guide/plan_modifications.rdoc +67 -0
- data/doc/guide/src/abstraction/achieve_with.page +8 -0
- data/doc/guide/src/abstraction/forwarding.page +8 -0
- data/doc/guide/src/abstraction/hierarchy.page +19 -0
- data/doc/guide/src/abstraction/index.page +28 -0
- data/doc/guide/src/abstraction/task_models.page +13 -0
- data/doc/guide/src/basics.template +6 -0
- data/doc/guide/src/basics/app.page +139 -0
- data/doc/guide/src/basics/code_examples.page +33 -0
- data/doc/guide/src/basics/dry.page +69 -0
- data/doc/guide/src/basics/errors.page +443 -0
- data/doc/guide/src/basics/events.page +179 -0
- data/doc/guide/src/basics/hierarchy.page +275 -0
- data/doc/guide/src/basics/index.page +11 -0
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/basics/plan_objects.page +71 -0
- data/doc/guide/src/basics/relations_display.page +203 -0
- data/doc/guide/src/basics/roby_cycle_overview.png +0 -0
- data/doc/guide/src/basics/shell.page +102 -0
- data/doc/guide/src/basics/summary.page +32 -0
- data/doc/guide/src/basics/tasks.page +357 -0
- data/doc/guide/src/basics_shell_header.txt +16 -0
- data/doc/guide/src/cycle/cycle-overview.png +0 -0
- data/doc/guide/src/cycle/cycle-overview.svg +208 -0
- data/doc/guide/src/cycle/error_handling.page +168 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.svg +1224 -0
- data/doc/guide/src/cycle/garbage_collection.page +10 -0
- data/doc/guide/src/cycle/index.page +23 -0
- data/doc/guide/src/cycle/propagation.page +154 -0
- data/doc/guide/src/cycle/propagation_diamond.png +0 -0
- data/doc/guide/src/cycle/propagation_diamond.svg +1279 -0
- data/doc/guide/src/default.css +319 -0
- data/doc/guide/src/default.template +74 -0
- data/doc/guide/src/htmldoc.metainfo +20 -0
- data/doc/guide/src/htmldoc.virtual +18 -0
- data/doc/guide/src/images/bodybg.png +0 -0
- data/doc/guide/src/images/contbg.png +0 -0
- data/doc/guide/src/images/footerbg.png +0 -0
- data/doc/guide/src/images/gradient1.png +0 -0
- data/doc/guide/src/images/gradient2.png +0 -0
- data/doc/guide/src/index.page +7 -0
- data/doc/guide/src/introduction/index.page +29 -0
- data/doc/guide/src/introduction/install.page +133 -0
- data/doc/{papers.rdoc → guide/src/introduction/publications.page} +5 -2
- data/doc/{videos.rdoc → guide/src/introduction/videos.page} +4 -2
- data/doc/guide/src/plugins/fault_tolerance.page +44 -0
- data/doc/guide/src/plugins/index.page +11 -0
- data/doc/guide/src/plugins/subsystems.page +45 -0
- data/doc/guide/src/relations/dependency.page +89 -0
- data/doc/guide/src/relations/index.page +12 -0
- data/doc/misc/update_github +24 -0
- data/doc/tutorials/02-GoForward.rdoc +3 -3
- data/ext/graph/graph.cc +46 -0
- data/lib/roby.rb +57 -22
- data/lib/roby/app.rb +132 -112
- data/lib/roby/app/plugins/rake.rb +21 -0
- data/lib/roby/app/rake.rb +0 -7
- data/lib/roby/app/run.rb +1 -1
- data/lib/roby/app/scripts/distributed.rb +1 -2
- data/lib/roby/app/scripts/generate/bookmarks.rb +1 -1
- data/lib/roby/app/scripts/results.rb +2 -1
- data/lib/roby/app/scripts/run.rb +6 -2
- data/lib/roby/app/scripts/shell.rb +11 -11
- data/lib/roby/config.rb +1 -1
- data/lib/roby/decision_control.rb +62 -3
- data/lib/roby/distributed.rb +4 -0
- data/lib/roby/distributed/base.rb +8 -0
- data/lib/roby/distributed/communication.rb +12 -8
- data/lib/roby/distributed/connection_space.rb +61 -44
- data/lib/roby/distributed/distributed_object.rb +1 -1
- data/lib/roby/distributed/notifications.rb +22 -30
- data/lib/roby/distributed/peer.rb +13 -8
- data/lib/roby/distributed/proxy.rb +5 -5
- data/lib/roby/distributed/subscription.rb +4 -4
- data/lib/roby/distributed/transaction.rb +3 -3
- data/lib/roby/event.rb +176 -110
- data/lib/roby/exceptions.rb +12 -4
- data/lib/roby/execution_engine.rb +1604 -0
- data/lib/roby/external_process_task.rb +225 -0
- data/lib/roby/graph.rb +0 -6
- data/lib/roby/interface.rb +221 -137
- data/lib/roby/log/console.rb +5 -3
- data/lib/roby/log/data_stream.rb +94 -16
- data/lib/roby/log/dot.rb +8 -8
- data/lib/roby/log/event_stream.rb +13 -3
- data/lib/roby/log/file.rb +43 -18
- data/lib/roby/log/gui/basic_display_ui.rb +89 -0
- data/lib/roby/log/gui/chronicle_view_ui.rb +90 -0
- data/lib/roby/log/gui/data_displays.rb +4 -5
- data/lib/roby/log/gui/data_displays_ui.rb +146 -0
- data/lib/roby/log/gui/relations.rb +18 -18
- data/lib/roby/log/gui/relations_ui.rb +120 -0
- data/lib/roby/log/gui/relations_view_ui.rb +144 -0
- data/lib/roby/log/gui/replay.rb +41 -13
- data/lib/roby/log/gui/replay_controls.rb +3 -0
- data/lib/roby/log/gui/replay_controls.ui +133 -110
- data/lib/roby/log/gui/replay_controls_ui.rb +249 -0
- data/lib/roby/log/hooks.rb +19 -18
- data/lib/roby/log/logger.rb +7 -6
- data/lib/roby/log/notifications.rb +4 -4
- data/lib/roby/log/plan_rebuilder.rb +20 -22
- data/lib/roby/log/relations.rb +44 -16
- data/lib/roby/log/server.rb +1 -4
- data/lib/roby/log/timings.rb +88 -19
- data/lib/roby/plan-object.rb +135 -11
- data/lib/roby/plan.rb +408 -224
- data/lib/roby/planning/loops.rb +32 -25
- data/lib/roby/planning/model.rb +157 -51
- data/lib/roby/planning/task.rb +47 -20
- data/lib/roby/query.rb +128 -92
- data/lib/roby/relations.rb +254 -136
- data/lib/roby/relations/conflicts.rb +6 -9
- data/lib/roby/relations/dependency.rb +358 -0
- data/lib/roby/relations/ensured.rb +0 -1
- data/lib/roby/relations/error_handling.rb +0 -1
- data/lib/roby/relations/events.rb +0 -2
- data/lib/roby/relations/executed_by.rb +26 -11
- data/lib/roby/relations/planned_by.rb +14 -14
- data/lib/roby/robot.rb +46 -0
- data/lib/roby/schedulers/basic.rb +34 -0
- data/lib/roby/standalone.rb +4 -0
- data/lib/roby/standard_errors.rb +21 -15
- data/lib/roby/state/events.rb +5 -4
- data/lib/roby/support.rb +107 -6
- data/lib/roby/task-operations.rb +23 -19
- data/lib/roby/task.rb +522 -148
- data/lib/roby/task_index.rb +80 -0
- data/lib/roby/test/common.rb +283 -44
- data/lib/roby/test/distributed.rb +53 -37
- data/lib/roby/test/testcase.rb +9 -204
- data/lib/roby/test/tools.rb +3 -3
- data/lib/roby/transactions.rb +154 -111
- data/lib/roby/transactions/proxy.rb +40 -7
- data/manifest.xml +20 -0
- data/plugins/fault_injection/README.txt +0 -3
- data/plugins/fault_injection/Rakefile +2 -8
- data/plugins/fault_injection/app.rb +1 -1
- data/plugins/fault_injection/fault_injection.rb +3 -3
- data/plugins/fault_injection/test/test_fault_injection.rb +19 -25
- data/plugins/subsystems/README.txt +0 -3
- data/plugins/subsystems/Rakefile +2 -7
- data/plugins/subsystems/app.rb +27 -16
- data/plugins/subsystems/test/app/config/init.rb +3 -0
- data/plugins/subsystems/test/app/planners/main.rb +1 -1
- data/plugins/subsystems/test/app/tasks/services.rb +1 -1
- data/plugins/subsystems/test/test_subsystems.rb +23 -16
- data/test/distributed/test_communication.rb +32 -15
- data/test/distributed/test_connection.rb +28 -26
- data/test/distributed/test_execution.rb +59 -54
- data/test/distributed/test_mixed_plan.rb +34 -34
- data/test/distributed/test_plan_notifications.rb +26 -26
- data/test/distributed/test_protocol.rb +57 -48
- data/test/distributed/test_query.rb +11 -7
- data/test/distributed/test_remote_plan.rb +71 -71
- data/test/distributed/test_transaction.rb +50 -47
- data/test/mockups/external_process +28 -0
- data/test/planning/test_loops.rb +163 -119
- data/test/planning/test_model.rb +3 -3
- data/test/planning/test_task.rb +27 -7
- data/test/relations/test_conflicts.rb +3 -3
- data/test/relations/test_dependency.rb +324 -0
- data/test/relations/test_ensured.rb +2 -2
- data/test/relations/test_executed_by.rb +94 -19
- data/test/relations/test_planned_by.rb +11 -9
- data/test/suite_core.rb +6 -3
- data/test/suite_distributed.rb +1 -0
- data/test/suite_planning.rb +1 -0
- data/test/suite_relations.rb +2 -2
- data/test/tasks/test_external_process.rb +126 -0
- data/test/{test_thread_task.rb → tasks/test_thread_task.rb} +17 -20
- data/test/test_bgl.rb +21 -1
- data/test/test_event.rb +229 -155
- data/test/test_exceptions.rb +79 -80
- data/test/test_execution_engine.rb +987 -0
- data/test/test_gui.rb +1 -1
- data/test/test_interface.rb +11 -5
- data/test/test_log.rb +18 -7
- data/test/test_log_server.rb +1 -0
- data/test/test_plan.rb +229 -395
- data/test/test_query.rb +193 -35
- data/test/test_relations.rb +88 -8
- data/test/test_state.rb +55 -37
- data/test/test_support.rb +1 -1
- data/test/test_task.rb +371 -218
- data/test/test_testcase.rb +32 -16
- data/test/test_transactions.rb +211 -170
- data/test/test_transactions_proxy.rb +37 -19
- metadata +169 -71
- data/.gitignore +0 -29
- data/doc/styles/allison.css +0 -314
- data/doc/styles/allison.js +0 -316
- data/doc/styles/allison.rb +0 -276
- data/doc/styles/jamis.rb +0 -593
- data/lib/roby/control.rb +0 -746
- data/lib/roby/executives/simple.rb +0 -30
- data/lib/roby/propagation.rb +0 -562
- data/lib/roby/relations/hierarchy.rb +0 -239
- data/lib/roby/transactions/updates.rb +0 -139
- data/test/relations/test_hierarchy.rb +0 -158
- data/test/test_control.rb +0 -399
- data/test/test_propagation.rb +0 -210
data/lib/roby/task.rb
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
require 'roby/plan-object'
|
|
2
|
-
require 'roby/exceptions'
|
|
3
|
-
require 'roby/event'
|
|
4
|
-
require 'utilrb/module/attr_predicate'
|
|
5
|
-
|
|
6
1
|
module Roby
|
|
7
2
|
class TaskModelTag < Module
|
|
8
3
|
module ClassExtension
|
|
9
4
|
# Returns the list of static arguments required by this task model
|
|
10
5
|
def arguments(*new_arguments)
|
|
11
6
|
new_arguments.each do |arg_name|
|
|
7
|
+
arg_name = arg_name.to_sym
|
|
12
8
|
argument_set << arg_name.to_sym
|
|
13
9
|
unless method_defined?(arg_name)
|
|
14
10
|
define_method(arg_name) { arguments[arg_name] }
|
|
11
|
+
define_method("#{arg_name}=") { |value| arguments[arg_name] = value }
|
|
15
12
|
end
|
|
16
13
|
end
|
|
17
14
|
|
|
@@ -19,6 +16,27 @@ module Roby
|
|
|
19
16
|
end
|
|
20
17
|
# Declares a set of arguments required by this task model
|
|
21
18
|
def argument(*args); arguments(*args) end
|
|
19
|
+
# The part of +arguments+ that is meaningful for this task model
|
|
20
|
+
def meaningful_arguments(arguments)
|
|
21
|
+
self_arguments = self.arguments.to_set
|
|
22
|
+
arguments.to_hash.delete_if do |key, _|
|
|
23
|
+
!self_arguments.include?(key)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Checks if this model fullfills everything in +models+
|
|
28
|
+
def fullfills?(models)
|
|
29
|
+
if !models.respond_to?(:each)
|
|
30
|
+
models = [models]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
for tag in models
|
|
34
|
+
if !has_ancestor?(tag)
|
|
35
|
+
return false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
true
|
|
39
|
+
end
|
|
22
40
|
end
|
|
23
41
|
include TaskModelTag::ClassExtension
|
|
24
42
|
|
|
@@ -46,6 +64,8 @@ module Roby
|
|
|
46
64
|
# The task which fired this event
|
|
47
65
|
attr_reader :task
|
|
48
66
|
|
|
67
|
+
def model; self.class end
|
|
68
|
+
|
|
49
69
|
def initialize(task, generator, propagation_id, context, time = Time.now)
|
|
50
70
|
@task = task
|
|
51
71
|
@terminal_flag = generator.terminal_flag
|
|
@@ -88,7 +108,7 @@ module Roby
|
|
|
88
108
|
# responds to #call
|
|
89
109
|
def self.controlable?; respond_to?(:call) end
|
|
90
110
|
# If the event is controlable
|
|
91
|
-
def controlable?;
|
|
111
|
+
def controlable?; model.controlable? end
|
|
92
112
|
class << self
|
|
93
113
|
# Called by Task.update_terminal_flag to update the flag
|
|
94
114
|
attr_writer :terminal
|
|
@@ -104,7 +124,7 @@ module Roby
|
|
|
104
124
|
# The event symbol
|
|
105
125
|
def self.symbol; @symbol end
|
|
106
126
|
# The event symbol
|
|
107
|
-
def symbol;
|
|
127
|
+
def symbol; model.symbol end
|
|
108
128
|
end
|
|
109
129
|
|
|
110
130
|
# A task event model bound to a particular task instance
|
|
@@ -140,9 +160,22 @@ module Roby
|
|
|
140
160
|
# by task.plan=. It is redefined here for performance reasons.
|
|
141
161
|
attr_accessor :plan
|
|
142
162
|
|
|
143
|
-
#
|
|
163
|
+
# Check that the event can be emitted
|
|
164
|
+
def emitting(context)
|
|
165
|
+
task.emitting_event(self, context)
|
|
166
|
+
super if defined? super
|
|
167
|
+
end
|
|
168
|
+
|
|
144
169
|
def fire(event)
|
|
145
170
|
task.fire_event(event)
|
|
171
|
+
super if defined? super
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def emit_failed(*reason)
|
|
175
|
+
if symbol == :start
|
|
176
|
+
task.failed_to_start = true
|
|
177
|
+
task.plan.task_index.set_state(task, :failed?)
|
|
178
|
+
end
|
|
146
179
|
super
|
|
147
180
|
end
|
|
148
181
|
|
|
@@ -153,13 +186,13 @@ module Roby
|
|
|
153
186
|
super if defined? super
|
|
154
187
|
if task.finished? && !terminal?
|
|
155
188
|
raise CommandFailed.new(nil, self),
|
|
156
|
-
"#{symbol}!(#{context})
|
|
189
|
+
"#{symbol}!(#{context}) called by #{plan.engine.propagation_sources.to_a} but the task has finished. Task has been terminated by #{task.event(:stop).history.first.sources}."
|
|
157
190
|
elsif task.pending? && symbol != :start
|
|
158
191
|
raise CommandFailed.new(nil, self),
|
|
159
|
-
"#{symbol}!(#{context})
|
|
192
|
+
"#{symbol}!(#{context}) called by #{plan.engine.propagation_sources.to_a} but the task has never been started"
|
|
160
193
|
elsif task.running? && symbol == :start
|
|
161
194
|
raise CommandFailed.new(nil, self),
|
|
162
|
-
"#{symbol}!(#{context})
|
|
195
|
+
"#{symbol}!(#{context}) called by #{plan.engine.propagation_sources.to_a} but the task is already running. Task has been started by #{task.event(:start).history.first.sources}."
|
|
163
196
|
end
|
|
164
197
|
end
|
|
165
198
|
|
|
@@ -219,7 +252,7 @@ module Roby
|
|
|
219
252
|
task.update_terminal_flag
|
|
220
253
|
end
|
|
221
254
|
end
|
|
222
|
-
def new(context); event_model.new(task, self,
|
|
255
|
+
def new(context); event_model.new(task, self, plan.engine.propagation_id, context) end
|
|
223
256
|
|
|
224
257
|
def to_s
|
|
225
258
|
"#{task}/#{symbol}"
|
|
@@ -238,8 +271,8 @@ module Roby
|
|
|
238
271
|
end
|
|
239
272
|
|
|
240
273
|
if child_task
|
|
241
|
-
unless task.
|
|
242
|
-
task.
|
|
274
|
+
unless task.depends_on?(child_task, false)
|
|
275
|
+
task.depends_on child_task,
|
|
243
276
|
:success => [child_event.symbol],
|
|
244
277
|
:remove_when_done => true
|
|
245
278
|
end
|
|
@@ -249,6 +282,13 @@ module Roby
|
|
|
249
282
|
end
|
|
250
283
|
end
|
|
251
284
|
|
|
285
|
+
# Refines exceptions that may be thrown by #call_without_propagation
|
|
286
|
+
def call_without_propagation(context)
|
|
287
|
+
super
|
|
288
|
+
rescue EventNotExecutable => e
|
|
289
|
+
refine_exception(e)
|
|
290
|
+
end
|
|
291
|
+
|
|
252
292
|
# Checks that the event can be called. Raises various exception
|
|
253
293
|
# when it is not the case.
|
|
254
294
|
def check_call_validity
|
|
@@ -268,23 +308,29 @@ module Roby
|
|
|
268
308
|
|
|
269
309
|
def refine_exception (e)
|
|
270
310
|
if task.partially_instanciated?
|
|
271
|
-
raise EventNotExecutable.new(self), "#{
|
|
311
|
+
raise EventNotExecutable.new(self), "#{symbol}! called on #{task} which is partially instanciated\n" +
|
|
272
312
|
"The following arguments were not set: \n" +
|
|
273
313
|
task.list_unset_arguments.map {|n| "\t#{n}"}.join("\n")+"\n"
|
|
274
314
|
#
|
|
275
315
|
elsif !plan
|
|
276
|
-
raise EventNotExecutable.new(self), "#{
|
|
316
|
+
raise EventNotExecutable.new(self), "#{symbol}! called on #{task} but the task is in no plan"
|
|
277
317
|
elsif !plan.executable?
|
|
278
|
-
raise EventNotExecutable.new(self), "#{
|
|
318
|
+
raise EventNotExecutable.new(self), "#{symbol}! called on #{task} but the plan is not executable"
|
|
279
319
|
elsif task.abstract?
|
|
280
|
-
raise EventNotExecutable.new(self), "#{
|
|
320
|
+
raise EventNotExecutable.new(self), "#{symbol}! called on #{task} but the task is abstract"
|
|
281
321
|
else
|
|
282
|
-
raise EventNotExecutable.new(self), "#{
|
|
322
|
+
raise EventNotExecutable.new(self), "#{symbol}! called on #{task} which is not executable: #{e.message}"
|
|
283
323
|
end
|
|
284
324
|
end
|
|
285
325
|
|
|
286
326
|
end
|
|
287
327
|
|
|
328
|
+
# Class that handles task arguments. They are handled specially as the
|
|
329
|
+
# arguments cannot be overwritten and can not be changed by a task that is
|
|
330
|
+
# not owned.
|
|
331
|
+
#
|
|
332
|
+
# Moreover, two hooks #updating and #updated allow to hook into the argument
|
|
333
|
+
# update system.
|
|
288
334
|
class TaskArguments < Hash
|
|
289
335
|
private :delete, :delete_if
|
|
290
336
|
|
|
@@ -305,6 +351,7 @@ module Roby
|
|
|
305
351
|
|
|
306
352
|
alias :update! :[]=
|
|
307
353
|
def []=(key, value)
|
|
354
|
+
key = key.to_sym if key.respond_to?(:to_str)
|
|
308
355
|
if writable?(key)
|
|
309
356
|
if !task.read_write?
|
|
310
357
|
raise OwnershipError, "cannot change the argument set of a task which is not owned #{task} is owned by #{task.owners} and #{task.plan} by #{task.plan.owners}"
|
|
@@ -320,6 +367,11 @@ module Roby
|
|
|
320
367
|
def updating; super if defined? super end
|
|
321
368
|
def updated; super if defined? super end
|
|
322
369
|
|
|
370
|
+
def [](key)
|
|
371
|
+
key = key.to_sym if key.respond_to?(:to_str)
|
|
372
|
+
super(key)
|
|
373
|
+
end
|
|
374
|
+
|
|
323
375
|
alias :do_merge! :merge!
|
|
324
376
|
def merge!(hash)
|
|
325
377
|
super do |key, old, new|
|
|
@@ -363,7 +415,7 @@ module Roby
|
|
|
363
415
|
# end
|
|
364
416
|
#
|
|
365
417
|
# event :other_event do |context|
|
|
366
|
-
#
|
|
418
|
+
# engine.once { emit :other_event }
|
|
367
419
|
# end
|
|
368
420
|
# end
|
|
369
421
|
#
|
|
@@ -371,6 +423,13 @@ module Roby
|
|
|
371
423
|
# immediately emitted, and in the second case it will be emitted at the
|
|
372
424
|
# beginning of the next execution cycle.
|
|
373
425
|
#
|
|
426
|
+
# === Task relations
|
|
427
|
+
#
|
|
428
|
+
# Task relations are defined in the TaskStructure RelationSpace instance.
|
|
429
|
+
# See TaskStructure documentation for the list of special methods defined
|
|
430
|
+
# by the various graphs, and the TaskStructure namespace for the name and
|
|
431
|
+
# purpose of the various relation graphs themselves.
|
|
432
|
+
#
|
|
374
433
|
# === Executability
|
|
375
434
|
#
|
|
376
435
|
# By default, a task is not executable, which means that no event command
|
|
@@ -420,7 +479,7 @@ module Roby
|
|
|
420
479
|
class_eval do
|
|
421
480
|
# Remove event models
|
|
422
481
|
events.each_key do |ev_symbol|
|
|
423
|
-
remove_const ev_symbol.to_s.
|
|
482
|
+
remove_const ev_symbol.to_s.camelcase(true)
|
|
424
483
|
end
|
|
425
484
|
|
|
426
485
|
[@events, @signal_sets, @forwarding_sets, @causal_link_sets,
|
|
@@ -461,6 +520,123 @@ module Roby
|
|
|
461
520
|
EOD
|
|
462
521
|
end
|
|
463
522
|
|
|
523
|
+
##
|
|
524
|
+
# :singleton-method: signals
|
|
525
|
+
# :call-seq:
|
|
526
|
+
# task_model.signals(event_model) => [target_event_models]
|
|
527
|
+
#
|
|
528
|
+
# Returns the set of model-level signal targets for the given event.
|
|
529
|
+
|
|
530
|
+
##
|
|
531
|
+
# :singleton-method: each_signal
|
|
532
|
+
# :call-seq:
|
|
533
|
+
# task_model.each_signal(event_model) do |target_event_model|
|
|
534
|
+
# end
|
|
535
|
+
#
|
|
536
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
537
|
+
# the given event. It enumerates all the ones defined on this model
|
|
538
|
+
# (using Task::signal) and also on its parent classes.
|
|
539
|
+
|
|
540
|
+
##
|
|
541
|
+
# :method: each_signal
|
|
542
|
+
# :call-seq:
|
|
543
|
+
# task.each_signal(event_model) do |target_event_model|
|
|
544
|
+
# end
|
|
545
|
+
#
|
|
546
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
547
|
+
# the given event. It enumerates all the ones defined on this task's model
|
|
548
|
+
# (using Task::signal) and also on its parent classes.
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
##
|
|
554
|
+
# :singleton-method: forwardings
|
|
555
|
+
# :call-seq:
|
|
556
|
+
# task_model.forwardings(event_model) => [target_event_models]
|
|
557
|
+
#
|
|
558
|
+
# Returns the set of model-level forwarding targets for the given event.
|
|
559
|
+
|
|
560
|
+
##
|
|
561
|
+
# :singleton-method: each_forwarding
|
|
562
|
+
# :call-seq:
|
|
563
|
+
# task_model.each_forwarding(event_model) do |target_event_model|
|
|
564
|
+
# end
|
|
565
|
+
#
|
|
566
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
567
|
+
# the given event. It enumerates all the ones defined on this model
|
|
568
|
+
# (using Task::forward) and also on its parent classes.
|
|
569
|
+
|
|
570
|
+
##
|
|
571
|
+
# :method: each_forwarding
|
|
572
|
+
# :call-seq:
|
|
573
|
+
# task.each_forwarding(event_model) do |target_event_model|
|
|
574
|
+
# end
|
|
575
|
+
#
|
|
576
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
577
|
+
# the given event. It enumerates all the ones defined on this task's
|
|
578
|
+
# model (using Task::forward) and also on its parent classes.
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
##
|
|
584
|
+
# :singleton-method: causal_links
|
|
585
|
+
# :call-seq:
|
|
586
|
+
# task_model.causal_links(event_model) => [target_event_models]
|
|
587
|
+
#
|
|
588
|
+
# Returns the set of model-level causal_link targets for the given event.
|
|
589
|
+
|
|
590
|
+
##
|
|
591
|
+
# :singleton-method: each_causal_link
|
|
592
|
+
# :call-seq:
|
|
593
|
+
# task_model.each_causal_link(event_model) do |target_event_model|
|
|
594
|
+
# end
|
|
595
|
+
#
|
|
596
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
597
|
+
# the given event. It enumerates all the ones defined on this model
|
|
598
|
+
# (using Task::causal_link) and also on its parent classes.
|
|
599
|
+
|
|
600
|
+
##
|
|
601
|
+
# :method: each_causal_link
|
|
602
|
+
# :call-seq:
|
|
603
|
+
# task.each_causal_link(event_model) do |target_event_model|
|
|
604
|
+
# end
|
|
605
|
+
#
|
|
606
|
+
# Enumerates the set of model-level causal links that are defined for
|
|
607
|
+
# the given event. It enumerates all the ones defined on this task's model
|
|
608
|
+
# (using Task::causal_link) and also on its parent classes.
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
##
|
|
614
|
+
# :singleton-method: handlers
|
|
615
|
+
# :call-seq:
|
|
616
|
+
# task_model.handlers(event_model) => [target_event_models]
|
|
617
|
+
#
|
|
618
|
+
# Returns the set of model-level event handlers for the given event.
|
|
619
|
+
|
|
620
|
+
##
|
|
621
|
+
# :singleton-method: each_handler
|
|
622
|
+
# :call-seq:
|
|
623
|
+
# task_model.each_handler(event_model) do |target_event_model|
|
|
624
|
+
# end
|
|
625
|
+
#
|
|
626
|
+
# Enumerates the set of model-level event handlers that are defined for
|
|
627
|
+
# the given event. It enumerates all handlers defined on the instance's
|
|
628
|
+
# task model and its parent classes.
|
|
629
|
+
|
|
630
|
+
##
|
|
631
|
+
# :method: each_handler
|
|
632
|
+
# :call-seq:
|
|
633
|
+
# task.each_handler(event_model) do |target_event_model|
|
|
634
|
+
# end
|
|
635
|
+
#
|
|
636
|
+
# Enumerates the set of model-level event handlers that are defined for
|
|
637
|
+
# the given event. It enumerates all handlers defined on the instance's
|
|
638
|
+
# task model and its parent classes.
|
|
639
|
+
|
|
464
640
|
model_attribute_list('signal')
|
|
465
641
|
model_attribute_list('forwarding')
|
|
466
642
|
model_attribute_list('causal_link')
|
|
@@ -469,13 +645,17 @@ module Roby
|
|
|
469
645
|
|
|
470
646
|
# The task arguments as symbol => value associative container
|
|
471
647
|
attr_reader :arguments
|
|
472
|
-
|
|
648
|
+
|
|
649
|
+
# The part of +arguments+ that is meaningful for this task model. I.e.
|
|
650
|
+
# it returns the set of elements in the +arguments+ property that define
|
|
651
|
+
# arguments listed in the task model
|
|
473
652
|
def meaningful_arguments(task_model = self.model)
|
|
474
653
|
arguments.slice(*task_model.arguments)
|
|
475
654
|
end
|
|
655
|
+
|
|
476
656
|
# The task name
|
|
477
657
|
def name
|
|
478
|
-
@name ||= "#{model.name || self.class.name}
|
|
658
|
+
@name ||= "#{model.name || self.class.name}:0x#{address.to_s(16)}"
|
|
479
659
|
end
|
|
480
660
|
|
|
481
661
|
# This predicate is true if this task is a mission for its owners. If
|
|
@@ -484,6 +664,7 @@ module Roby
|
|
|
484
664
|
|
|
485
665
|
def inspect
|
|
486
666
|
state = if pending? then 'pending'
|
|
667
|
+
elsif failed_to_start? then 'failed to start'
|
|
487
668
|
elsif starting? then 'starting'
|
|
488
669
|
elsif running? then 'running'
|
|
489
670
|
elsif finishing? then 'finishing'
|
|
@@ -499,23 +680,34 @@ module Roby
|
|
|
499
680
|
# * the task shall have a +start+ event
|
|
500
681
|
# * the task shall have at least one terminal event. If no +stop+ event
|
|
501
682
|
# is defined, then all terminal events are aliased to +stop+
|
|
502
|
-
def initialize(arguments =
|
|
683
|
+
def initialize(arguments = Hash.new) #:yields: task_object
|
|
503
684
|
super() if defined? super
|
|
504
685
|
|
|
505
686
|
@arguments = TaskArguments.new(self)
|
|
506
|
-
|
|
687
|
+
arguments.each do |key, value|
|
|
688
|
+
if self.respond_to?("#{key}=")
|
|
689
|
+
self.send("#{key}=", value)
|
|
690
|
+
else
|
|
691
|
+
@arguments[key] = value
|
|
692
|
+
end
|
|
693
|
+
end
|
|
507
694
|
|
|
508
695
|
@model = self.class
|
|
509
696
|
|
|
510
697
|
yield(self) if block_given?
|
|
698
|
+
# Create the EventGenerator instances that represent this task's
|
|
699
|
+
# events. Note that the event relations are instanciated by
|
|
700
|
+
# Plan#discover when this task is included in a plan, thus avoiding
|
|
701
|
+
# filling up the relation graphs with unused relations.
|
|
511
702
|
initialize_events
|
|
512
703
|
end
|
|
513
704
|
|
|
514
705
|
|
|
515
706
|
# Lists all arguments, that are set to be needed via the :argument
|
|
516
707
|
# syntax but are not set.
|
|
708
|
+
#
|
|
517
709
|
# This is needed for debugging purposes.
|
|
518
|
-
def list_unset_arguments
|
|
710
|
+
def list_unset_arguments # :nodoc:
|
|
519
711
|
ret = Array.new
|
|
520
712
|
model.arguments.each { |name|
|
|
521
713
|
if !arguments.has_key?(name) then
|
|
@@ -523,7 +715,6 @@ module Roby
|
|
|
523
715
|
end }
|
|
524
716
|
ret
|
|
525
717
|
end
|
|
526
|
-
|
|
527
718
|
|
|
528
719
|
# Helper methods which creates all the necessary TaskEventGenerator
|
|
529
720
|
# objects and stores them in the #bound_events map
|
|
@@ -540,6 +731,25 @@ module Roby
|
|
|
540
731
|
|
|
541
732
|
def model; self.class end
|
|
542
733
|
|
|
734
|
+
# Returns for how many seconds this task is running. Returns nil if
|
|
735
|
+
# the task is not running.
|
|
736
|
+
def lifetime
|
|
737
|
+
if running?
|
|
738
|
+
Time.now - history.first.time
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
# Returns when this task has been started
|
|
743
|
+
def start_time
|
|
744
|
+
if running?
|
|
745
|
+
history.first.time
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def create_fresh_copy
|
|
750
|
+
model.new(arguments.dup)
|
|
751
|
+
end
|
|
752
|
+
|
|
543
753
|
def initialize_copy(old) # :nodoc:
|
|
544
754
|
super
|
|
545
755
|
|
|
@@ -551,7 +761,7 @@ module Roby
|
|
|
551
761
|
arguments.instance_variable_set(:@task, self)
|
|
552
762
|
|
|
553
763
|
initialize_events
|
|
554
|
-
plan.
|
|
764
|
+
plan.add(self)
|
|
555
765
|
end
|
|
556
766
|
|
|
557
767
|
def instantiate_model_event_relations
|
|
@@ -569,7 +779,7 @@ module Roby
|
|
|
569
779
|
|
|
570
780
|
for signalled in signalled_events
|
|
571
781
|
signalled = bound_events[signalled]
|
|
572
|
-
generator.
|
|
782
|
+
generator.signals signalled
|
|
573
783
|
left_border.delete(signalled)
|
|
574
784
|
end
|
|
575
785
|
end
|
|
@@ -582,7 +792,7 @@ module Roby
|
|
|
582
792
|
|
|
583
793
|
for signalled in signalled_events
|
|
584
794
|
signalled = bound_events[signalled]
|
|
585
|
-
generator.
|
|
795
|
+
generator.forward_to signalled
|
|
586
796
|
left_border.delete(signalled)
|
|
587
797
|
end
|
|
588
798
|
end
|
|
@@ -646,29 +856,44 @@ module Roby
|
|
|
646
856
|
end
|
|
647
857
|
|
|
648
858
|
class << self
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
859
|
+
##
|
|
860
|
+
# :singleton-method: abstract?
|
|
861
|
+
#
|
|
862
|
+
# True if this task is an abstract task.
|
|
863
|
+
#
|
|
864
|
+
# See Task::abstract() for more information.
|
|
865
|
+
attr_predicate :abstract
|
|
866
|
+
|
|
867
|
+
# Declare that this task model defines abstract tasks. Abstract
|
|
868
|
+
# tasks can be used to represent an action, without specifically
|
|
869
|
+
# representing how this action should be done.
|
|
870
|
+
#
|
|
871
|
+
# Instances of abstract task models are not executable, i.e. they
|
|
872
|
+
# cannot be started.
|
|
873
|
+
#
|
|
874
|
+
# See also #abstract? and #executable?
|
|
656
875
|
def abstract
|
|
657
876
|
@abstract = true
|
|
658
877
|
end
|
|
659
878
|
|
|
660
|
-
# Declare that
|
|
661
|
-
#
|
|
662
|
-
#
|
|
663
|
-
#
|
|
879
|
+
# Declare that tasks of this model can finish by simply emitting
|
|
880
|
+
# +stop+. Use it this way:
|
|
881
|
+
#
|
|
882
|
+
# class MyTask < Roby::Task
|
|
883
|
+
# terminates
|
|
884
|
+
# end
|
|
885
|
+
#
|
|
886
|
+
# It adds a +stop!+ command that emits the +failed+ event.
|
|
664
887
|
def terminates
|
|
665
888
|
event :failed, :command => true, :terminal => true
|
|
666
889
|
interruptible
|
|
667
890
|
end
|
|
668
891
|
|
|
669
|
-
#
|
|
670
|
-
#
|
|
671
|
-
#
|
|
892
|
+
# Declare that tasks of this model can be interrupted. It does so by
|
|
893
|
+
# defining a command for +stop+, which in effect calls the command
|
|
894
|
+
# for +failed+.
|
|
895
|
+
#
|
|
896
|
+
# Raises ArgumentError if failed is not controlable.
|
|
672
897
|
def interruptible
|
|
673
898
|
if !has_event?(:failed) || !event_model(:failed).controlable?
|
|
674
899
|
raise ArgumentError, "failed is not controlable"
|
|
@@ -683,7 +908,7 @@ module Roby
|
|
|
683
908
|
end
|
|
684
909
|
|
|
685
910
|
def setup_poll_method(block) # :nodoc:
|
|
686
|
-
define_method(:poll) do
|
|
911
|
+
define_method(:poll) do |plan|
|
|
687
912
|
return unless self_owned?
|
|
688
913
|
begin
|
|
689
914
|
poll_handler
|
|
@@ -695,9 +920,17 @@ module Roby
|
|
|
695
920
|
define_method(:poll_handler, &block)
|
|
696
921
|
end
|
|
697
922
|
|
|
698
|
-
#
|
|
699
|
-
#
|
|
700
|
-
#
|
|
923
|
+
# Declares that the given block should be called at each execution
|
|
924
|
+
# cycle, when the task is running. Use it that way:
|
|
925
|
+
#
|
|
926
|
+
# class MyTask < Roby::Task
|
|
927
|
+
# poll do
|
|
928
|
+
# ... do something ...
|
|
929
|
+
# end
|
|
930
|
+
# end
|
|
931
|
+
#
|
|
932
|
+
# If the given polling block raises an exception, the task will be
|
|
933
|
+
# terminated by emitting its +failed+ event.
|
|
701
934
|
def poll(&block)
|
|
702
935
|
if !block_given?
|
|
703
936
|
raise "no block given"
|
|
@@ -705,8 +938,8 @@ module Roby
|
|
|
705
938
|
|
|
706
939
|
setup_poll_method(block)
|
|
707
940
|
|
|
708
|
-
on(:start) {
|
|
709
|
-
on(:stop) {
|
|
941
|
+
on(:start) { |ev| ev.task.plan.engine.propagation_handlers << method(:poll) }
|
|
942
|
+
on(:stop) { |ev| ev.task.plan.engine.propagation_handlers.delete(method(:poll)) }
|
|
710
943
|
end
|
|
711
944
|
end
|
|
712
945
|
|
|
@@ -715,8 +948,13 @@ module Roby
|
|
|
715
948
|
|
|
716
949
|
# Returns true if this task is from an abstract model. If it is the
|
|
717
950
|
# case, the task is not executable.
|
|
718
|
-
|
|
719
|
-
|
|
951
|
+
#
|
|
952
|
+
# See Task::abstract for more details.
|
|
953
|
+
def abstract?; model.abstract? end
|
|
954
|
+
# True if this task is executable. A task is not executable if it is
|
|
955
|
+
# abstract or partially instanciated.
|
|
956
|
+
#
|
|
957
|
+
# See #abstract? and #partially_instanciated?
|
|
720
958
|
def executable?; !abstract? && !partially_instanciated? && super end
|
|
721
959
|
# Returns true if this task's stop event is controlable
|
|
722
960
|
def interruptible?; event(:stop).controlable? end
|
|
@@ -745,14 +983,14 @@ module Roby
|
|
|
745
983
|
# can either be a event class or an event name.
|
|
746
984
|
def has_event?(event_model)
|
|
747
985
|
bound_events.has_key?(event_model) ||
|
|
748
|
-
|
|
986
|
+
model.has_event?(event_model)
|
|
749
987
|
end
|
|
750
988
|
|
|
751
989
|
# True if this task is starting, i.e. if its start event is pending
|
|
752
990
|
# (has been called, but is not emitted yet)
|
|
753
991
|
def starting?; event(:start).pending? end
|
|
754
992
|
# True if this task has never been started
|
|
755
|
-
def pending?; !starting? && !started? end
|
|
993
|
+
def pending?; !failed_to_start? && !starting? && !started? end
|
|
756
994
|
# True if this task is currently running (i.e. is has already started,
|
|
757
995
|
# and is not finished)
|
|
758
996
|
def running?; started? && !finished? end
|
|
@@ -767,14 +1005,24 @@ module Roby
|
|
|
767
1005
|
attr_predicate :started?, true
|
|
768
1006
|
attr_predicate :finished?, true
|
|
769
1007
|
attr_predicate :success?, true
|
|
1008
|
+
attr_predicate :failed_to_start?, true
|
|
770
1009
|
|
|
771
1010
|
# True if the +failed+ event of this task has been fired
|
|
772
|
-
def failed?; finished? && @success == false end
|
|
1011
|
+
def failed?; failed_to_start? || (finished? && @success == false) end
|
|
773
1012
|
|
|
774
|
-
#
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1013
|
+
# call-seq:
|
|
1014
|
+
# task.clear_relations => task
|
|
1015
|
+
#
|
|
1016
|
+
# Remove all relations in which +self+ or its event are involved
|
|
1017
|
+
#--
|
|
1018
|
+
# The including_events flag is here for the benefit of
|
|
1019
|
+
# Transactions::Proxy::Task only
|
|
1020
|
+
def clear_relations(including_events = true)
|
|
1021
|
+
if including_events
|
|
1022
|
+
each_event { |ev| ev.clear_relations }
|
|
1023
|
+
end
|
|
1024
|
+
super()
|
|
1025
|
+
self
|
|
778
1026
|
end
|
|
779
1027
|
|
|
780
1028
|
# Update the terminal flag for the event models that are defined in
|
|
@@ -863,8 +1111,8 @@ module Roby
|
|
|
863
1111
|
end
|
|
864
1112
|
end
|
|
865
1113
|
|
|
866
|
-
# Returns a
|
|
867
|
-
#
|
|
1114
|
+
# Returns a list of Event objects, for all events that have been fired
|
|
1115
|
+
# by this task. The list is sorted by emission times.
|
|
868
1116
|
def history
|
|
869
1117
|
history = []
|
|
870
1118
|
each_event do |event|
|
|
@@ -874,9 +1122,9 @@ module Roby
|
|
|
874
1122
|
history.sort_by { |ev| ev.time }
|
|
875
1123
|
end
|
|
876
1124
|
|
|
877
|
-
# Returns the set of tasks directly related to this task, either
|
|
878
|
-
#
|
|
879
|
-
#
|
|
1125
|
+
# Returns the set of tasks directly related to this task, either because
|
|
1126
|
+
# of task relations or because of task events that are related to other
|
|
1127
|
+
# task events
|
|
880
1128
|
def related_tasks(result = nil)
|
|
881
1129
|
result = related_objects(nil, result)
|
|
882
1130
|
each_event do |ev|
|
|
@@ -898,29 +1146,41 @@ module Roby
|
|
|
898
1146
|
|
|
899
1147
|
# This method is called by TaskEventGenerator#fire just before the event handlers
|
|
900
1148
|
# and commands are called
|
|
901
|
-
def
|
|
1149
|
+
def emitting_event(event, context) # :nodoc:
|
|
902
1150
|
if !executable?
|
|
903
|
-
raise TaskNotExecutable.new(self), "trying to
|
|
1151
|
+
raise TaskNotExecutable.new(self), "trying to emit #{symbol} on #{self} but #{self} is not executable"
|
|
904
1152
|
end
|
|
905
1153
|
|
|
906
1154
|
if finished? && !event.terminal?
|
|
907
|
-
raise EmissionFailed.new(nil, self),
|
|
908
|
-
"emit(#{event.symbol}
|
|
1155
|
+
raise EmissionFailed.new(nil, self),
|
|
1156
|
+
"emit(#{event.symbol}, #{context}) called by #{plan.engine.propagation_sources.to_a} but the task has finished. Task has been terminated by #{event(:stop).history.first.sources}."
|
|
909
1157
|
elsif pending? && event.symbol != :start
|
|
910
|
-
raise EmissionFailed.new(nil, self),
|
|
911
|
-
"emit(#{event.symbol}
|
|
1158
|
+
raise EmissionFailed.new(nil, self),
|
|
1159
|
+
"emit(#{event.symbol}, #{context}) called by #{plan.engine.propagation_sources.to_a} but the task has never been started"
|
|
912
1160
|
elsif running? && event.symbol == :start
|
|
913
|
-
raise EmissionFailed.new(nil, self),
|
|
914
|
-
"emit(#{event.symbol}
|
|
1161
|
+
raise EmissionFailed.new(nil, self),
|
|
1162
|
+
"emit(#{event.symbol}, #{context}) called by #{plan.engine.propagation_sources.to_a} but the task is already running. Task has been started by #{event(:start).history.first.sources}."
|
|
915
1163
|
end
|
|
916
1164
|
|
|
917
|
-
|
|
1165
|
+
super if defined? super
|
|
1166
|
+
end
|
|
918
1167
|
|
|
1168
|
+
# Hook called by TaskEventGenerator#fired when one of this task's events
|
|
1169
|
+
# is fired.
|
|
1170
|
+
def fire_event(event)
|
|
1171
|
+
update_task_status(event)
|
|
919
1172
|
super if defined? super
|
|
920
1173
|
end
|
|
921
1174
|
|
|
922
1175
|
# The event which has finished the task (if there is one)
|
|
923
1176
|
attr_reader :terminal_event
|
|
1177
|
+
|
|
1178
|
+
# The event that caused this task to fail. This is equivalent to taking
|
|
1179
|
+
# the first emitted element of
|
|
1180
|
+
# task.event(:failed).last.task_sources
|
|
1181
|
+
#
|
|
1182
|
+
# It is only much more efficient
|
|
1183
|
+
attr_reader :failure_event
|
|
924
1184
|
|
|
925
1185
|
# Call to update the task status because of +event+
|
|
926
1186
|
def update_task_status(event) # :nodoc:
|
|
@@ -934,6 +1194,7 @@ module Roby
|
|
|
934
1194
|
self.success = false
|
|
935
1195
|
self.finished = true
|
|
936
1196
|
@terminal_event ||= event
|
|
1197
|
+
@failure_event ||= event
|
|
937
1198
|
elsif event.terminal? && !finished?
|
|
938
1199
|
plan.task_index.set_state(self, :finished?)
|
|
939
1200
|
self.finished = true
|
|
@@ -974,22 +1235,42 @@ module Roby
|
|
|
974
1235
|
end
|
|
975
1236
|
|
|
976
1237
|
# call-seq:
|
|
977
|
-
# on(event, task[, event1, event2, ...])
|
|
978
1238
|
# on(event) { |event| ... }
|
|
979
|
-
# on(event[, task, event1, event2, ...]) { |event| ... }
|
|
980
|
-
# on(event, task[, event1, event2, ...], delay)
|
|
981
|
-
#
|
|
982
|
-
# Adds a signal from the given event to the specified targets, and/or
|
|
983
|
-
# defines an event handler. Note that <tt>on(event, task)</tt> is
|
|
984
|
-
# equivalent to <tt>on(event, task, event)</tt>
|
|
985
1239
|
#
|
|
986
|
-
#
|
|
987
|
-
# much time as specified. See EventGenerator#signal for valid values.
|
|
1240
|
+
# Defines an event handler for the given event.
|
|
988
1241
|
def on(event_model, to = nil, *to_task_events, &user_handler)
|
|
989
|
-
|
|
1242
|
+
if to
|
|
1243
|
+
Roby.warn_deprecated "on(event_name, task, target_events) has been replaced by #signals"
|
|
1244
|
+
elsif !(to || user_handler)
|
|
990
1245
|
raise ArgumentError, "you must provide either a task or an event handler (got nil for both)"
|
|
991
1246
|
end
|
|
992
1247
|
|
|
1248
|
+
if to
|
|
1249
|
+
signals(event_model, to, *to_task_events)
|
|
1250
|
+
end
|
|
1251
|
+
if user_handler
|
|
1252
|
+
generator = event(event_model)
|
|
1253
|
+
generator.on(&user_handler)
|
|
1254
|
+
end
|
|
1255
|
+
self
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1258
|
+
# call-seq:
|
|
1259
|
+
# signals source_event, dest_task, ev1, ev2, ev3, ...
|
|
1260
|
+
# signals source_event, dest_task, ev1, ev2, ev3, delay_options
|
|
1261
|
+
#
|
|
1262
|
+
# Creates a signal from +source_event+, which is an event name of
|
|
1263
|
+
# +self+, to the listed events of +dest_task+. The destination events
|
|
1264
|
+
# will be called when the source event is emitted.
|
|
1265
|
+
#
|
|
1266
|
+
# To simply emit target events (i.e. not calling the event's commands),
|
|
1267
|
+
# use #forwards
|
|
1268
|
+
#
|
|
1269
|
+
# Optionally, a delay can be added to the signal. +delay_options+ can be
|
|
1270
|
+
# either:
|
|
1271
|
+
# :delay => relative_delay_in_seconds
|
|
1272
|
+
# :at => absolute_time
|
|
1273
|
+
def signals(event_model, to, *to_task_events)
|
|
993
1274
|
generator = event(event_model)
|
|
994
1275
|
if Hash === to_task_events.last
|
|
995
1276
|
delay = to_task_events.pop
|
|
@@ -997,6 +1278,7 @@ module Roby
|
|
|
997
1278
|
to_events = case to
|
|
998
1279
|
when Task
|
|
999
1280
|
if to_task_events.empty?
|
|
1281
|
+
Roby.warn_deprecated "signals(event_name, target_task) is deprecated. You must now always specify the target event name"
|
|
1000
1282
|
[to.event(generator.symbol)]
|
|
1001
1283
|
else
|
|
1002
1284
|
to_task_events.map { |ev_model| to.event(ev_model) }
|
|
@@ -1006,27 +1288,35 @@ module Roby
|
|
|
1006
1288
|
end
|
|
1007
1289
|
|
|
1008
1290
|
to_events.push delay if delay
|
|
1009
|
-
generator.
|
|
1291
|
+
generator.signals(*to_events)
|
|
1010
1292
|
self
|
|
1011
1293
|
end
|
|
1012
1294
|
|
|
1295
|
+
def forward(name, to, *to_task_events)
|
|
1296
|
+
Roby.warn_deprecated "Task#forward has been renamed into Task#forward_to"
|
|
1297
|
+
if to_task_events.empty?
|
|
1298
|
+
Roby.warn_deprecated "the Task#forward(event_name, target_task) form is deprecated. Use Task#forward_to and specify the target event name"
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
forward_to(name, to, *to_task_events)
|
|
1302
|
+
end
|
|
1303
|
+
|
|
1013
1304
|
# call-seq:
|
|
1014
|
-
#
|
|
1015
|
-
#
|
|
1305
|
+
# forward_to source_event, dest_task, ev1, ev2, ev3, ...
|
|
1306
|
+
# forward_to source_event, dest_task, ev1, ev2, ev3, delay_options
|
|
1016
1307
|
#
|
|
1017
|
-
# Fowards +
|
|
1018
|
-
#
|
|
1019
|
-
#
|
|
1308
|
+
# Fowards the +source_event+, which is the name of an event of +self+,
|
|
1309
|
+
# to the listed events in +dest_task+. The target events will be emitted
|
|
1310
|
+
# as soon as the source event is emitted,
|
|
1020
1311
|
#
|
|
1021
1312
|
# To call an event whenever other events are emitted, use the Signal
|
|
1022
|
-
# relation. See Task#
|
|
1023
|
-
# <tt>forward(:start, task)</tt> is a shortcut to <tt>forward(:start,
|
|
1024
|
-
# task, :start)</tt>.
|
|
1313
|
+
# relation. See Task#signals, Task.signal and EventGenerator#signals.
|
|
1025
1314
|
#
|
|
1026
|
-
#
|
|
1027
|
-
#
|
|
1028
|
-
#
|
|
1029
|
-
|
|
1315
|
+
# Optionally, a delay can be added to the signal. +delay_options+ can be
|
|
1316
|
+
# either:
|
|
1317
|
+
# :delay => relative_delay_in_seconds
|
|
1318
|
+
# :at => absolute_time
|
|
1319
|
+
def forward_to(name, to, *to_task_events)
|
|
1030
1320
|
generator = event(name)
|
|
1031
1321
|
if Hash === to_task_events.last
|
|
1032
1322
|
delay = to_task_events.pop
|
|
@@ -1034,10 +1324,11 @@ module Roby
|
|
|
1034
1324
|
|
|
1035
1325
|
to_events = if to.respond_to?(:event)
|
|
1036
1326
|
if to_task_events.empty?
|
|
1327
|
+
Roby.warn_deprecated "forward_to(event_name, target_task) is deprecated. You must now always specify the target event name"
|
|
1037
1328
|
[to.event(generator.symbol)]
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1329
|
+
else
|
|
1330
|
+
to_task_events.map { |ev| to.event(ev) }
|
|
1331
|
+
end
|
|
1041
1332
|
elsif to.kind_of?(EventGenerator)
|
|
1042
1333
|
[to]
|
|
1043
1334
|
else
|
|
@@ -1045,31 +1336,44 @@ module Roby
|
|
|
1045
1336
|
end
|
|
1046
1337
|
|
|
1047
1338
|
to_events.each do |ev|
|
|
1048
|
-
generator.
|
|
1339
|
+
generator.forward_to ev, delay
|
|
1049
1340
|
end
|
|
1050
1341
|
end
|
|
1051
1342
|
|
|
1343
|
+
# :stopdoc:
|
|
1052
1344
|
attr_accessor :calling_event
|
|
1345
|
+
|
|
1053
1346
|
def method_missing(name, *args, &block) # :nodoc:
|
|
1054
1347
|
if calling_event && calling_event.respond_to?(name)
|
|
1055
1348
|
calling_event.send(name, *args, &block)
|
|
1056
1349
|
else
|
|
1057
1350
|
super
|
|
1058
1351
|
end
|
|
1059
|
-
rescue
|
|
1060
|
-
raise
|
|
1352
|
+
rescue NameError => e
|
|
1353
|
+
raise e, e.message, caller(1)
|
|
1354
|
+
rescue NoMethodError => e
|
|
1355
|
+
raise e, e.message, caller(1)
|
|
1061
1356
|
end
|
|
1062
1357
|
|
|
1358
|
+
# Declares that this task model provides the given interface. +model+
|
|
1359
|
+
# must be an instance of TaskModelTag
|
|
1360
|
+
def self.provides(model)
|
|
1361
|
+
include model
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
|
|
1063
1365
|
@@event_command_id = 0
|
|
1064
1366
|
def self.allocate_event_command_id # :nodoc:
|
|
1065
1367
|
@@event_command_id += 1
|
|
1066
1368
|
end
|
|
1369
|
+
# :startdoc:
|
|
1370
|
+
|
|
1067
1371
|
# call-seq:
|
|
1068
|
-
# self.event(name, options = nil) { ... }
|
|
1372
|
+
# self.event(name, options = nil) { ... } => event class or nil
|
|
1069
1373
|
#
|
|
1070
1374
|
# Define a new event in this task.
|
|
1071
1375
|
#
|
|
1072
|
-
#
|
|
1376
|
+
# <b>Available options</b>
|
|
1073
1377
|
#
|
|
1074
1378
|
# <tt>command</tt>::
|
|
1075
1379
|
# either true, false or an event command for the new event. In that
|
|
@@ -1086,7 +1390,7 @@ module Roby
|
|
|
1086
1390
|
# base class for the event model (see "Event models" below). The default is the
|
|
1087
1391
|
# TaskEvent class
|
|
1088
1392
|
#
|
|
1089
|
-
#
|
|
1393
|
+
# <b>Event models</b>
|
|
1090
1394
|
#
|
|
1091
1395
|
# When a task event (for instance +start+) is emitted, a Roby::Event
|
|
1092
1396
|
# object is created to describe the information related to this
|
|
@@ -1130,10 +1434,10 @@ module Roby
|
|
|
1130
1434
|
@symbol = ev
|
|
1131
1435
|
@command_handler = command_handler
|
|
1132
1436
|
|
|
1133
|
-
define_method(:name) { "#{task.name}::#{ev_s.
|
|
1437
|
+
define_method(:name) { "#{task.name}::#{ev_s.camelcase(true)}" }
|
|
1134
1438
|
singleton_class.class_eval do
|
|
1135
1439
|
attr_reader :command_handler
|
|
1136
|
-
define_method(:name) { "#{task_klass.name}::#{ev_s.
|
|
1440
|
+
define_method(:name) { "#{task_klass.name}::#{ev_s.camelcase(true)}" }
|
|
1137
1441
|
def to_s; name end
|
|
1138
1442
|
end
|
|
1139
1443
|
end
|
|
@@ -1148,7 +1452,7 @@ module Roby
|
|
|
1148
1452
|
if setup_terminal_handler
|
|
1149
1453
|
forward(new_event => :stop)
|
|
1150
1454
|
end
|
|
1151
|
-
const_set(ev_s.
|
|
1455
|
+
const_set(ev_s.camelcase(true), new_event)
|
|
1152
1456
|
|
|
1153
1457
|
if options[:command]
|
|
1154
1458
|
# check that the supplied command handler can take two arguments
|
|
@@ -1172,6 +1476,17 @@ module Roby
|
|
|
1172
1476
|
end
|
|
1173
1477
|
end
|
|
1174
1478
|
|
|
1479
|
+
if !method_defined?("#{ev_s}_event")
|
|
1480
|
+
define_method("#{ev_s}_event") do
|
|
1481
|
+
event(ev)
|
|
1482
|
+
end
|
|
1483
|
+
end
|
|
1484
|
+
if !method_defined?("#{ev_s}?")
|
|
1485
|
+
define_method("#{ev_s}?") do
|
|
1486
|
+
event(ev).happened?
|
|
1487
|
+
end
|
|
1488
|
+
end
|
|
1489
|
+
|
|
1175
1490
|
new_event
|
|
1176
1491
|
end
|
|
1177
1492
|
|
|
@@ -1201,15 +1516,23 @@ module Roby
|
|
|
1201
1516
|
|
|
1202
1517
|
# Events defined by the task model
|
|
1203
1518
|
inherited_enumerable(:event, :events, :map => true) { Hash.new }
|
|
1204
|
-
|
|
1519
|
+
|
|
1520
|
+
def self.enum_events # :nodoc
|
|
1205
1521
|
@__enum_events__ ||= enum_for(:each_event)
|
|
1206
1522
|
end
|
|
1207
1523
|
|
|
1524
|
+
# call-seq:
|
|
1525
|
+
# task.each_event { |event_object| ... } => task
|
|
1526
|
+
#
|
|
1208
1527
|
# Iterates on all the events defined for this task
|
|
1209
|
-
|
|
1528
|
+
#--
|
|
1529
|
+
# The +only_wrapped+ flag is here for consistency with transaction
|
|
1530
|
+
# proxies, and should probably not be used in user code.
|
|
1531
|
+
def each_event(only_wrapped = true) # :yield:bound_event
|
|
1210
1532
|
for _, ev in bound_events
|
|
1211
1533
|
yield(ev)
|
|
1212
1534
|
end
|
|
1535
|
+
self
|
|
1213
1536
|
end
|
|
1214
1537
|
alias :each_plan_child :each_event
|
|
1215
1538
|
|
|
@@ -1271,8 +1594,34 @@ module Roby
|
|
|
1271
1594
|
end
|
|
1272
1595
|
|
|
1273
1596
|
# call-seq:
|
|
1274
|
-
#
|
|
1275
|
-
#
|
|
1597
|
+
# signal(name1 => name2, name3 => [name4, name5])
|
|
1598
|
+
#
|
|
1599
|
+
# Establish model-level signals between events of that task. These
|
|
1600
|
+
# signals will be established on all the instances of this task model
|
|
1601
|
+
# (and its subclasses).
|
|
1602
|
+
def self.signal(mappings)
|
|
1603
|
+
mappings.each do |from, to|
|
|
1604
|
+
from = event_model(from)
|
|
1605
|
+
targets = Array[*to].map { |ev| event_model(ev) }
|
|
1606
|
+
|
|
1607
|
+
if from.terminal?
|
|
1608
|
+
non_terminal = targets.find_all { |ev| !ev.terminal? }
|
|
1609
|
+
if !non_terminal.empty?
|
|
1610
|
+
raise ArgumentError, "trying to establish a forwarding relation from the terminal event #{from} to the non-terminal events #{non_terminal}"
|
|
1611
|
+
end
|
|
1612
|
+
end
|
|
1613
|
+
non_controlable = targets.find_all { |ev| !ev.controlable? }
|
|
1614
|
+
if !non_controlable.empty?
|
|
1615
|
+
raise ArgumentError, "trying to signal #{non_controlable.join(" ")} which is/are not controlable"
|
|
1616
|
+
end
|
|
1617
|
+
|
|
1618
|
+
signal_sets[from.symbol].merge targets.map { |ev| ev.symbol }.to_value_set
|
|
1619
|
+
end
|
|
1620
|
+
update_terminal_flag
|
|
1621
|
+
end
|
|
1622
|
+
|
|
1623
|
+
# call-seq:
|
|
1624
|
+
# on(event_name) { |event| ... }
|
|
1276
1625
|
#
|
|
1277
1626
|
# Adds an event handler for the given event model. When the event is fired,
|
|
1278
1627
|
# all events given in argument will be called. If they are controlable,
|
|
@@ -1282,21 +1631,14 @@ module Roby
|
|
|
1282
1631
|
check_arity(user_handler, 1)
|
|
1283
1632
|
end
|
|
1284
1633
|
|
|
1634
|
+
if mappings.kind_of?(Hash)
|
|
1635
|
+
Roby.warn_deprecated "the on(event => event) form of Task.on is deprecated. Use #signal to establish signals"
|
|
1636
|
+
signal(mappings)
|
|
1637
|
+
end
|
|
1638
|
+
|
|
1285
1639
|
mappings = [*mappings].zip([]) unless Hash === mappings
|
|
1286
|
-
mappings.each do |from,
|
|
1640
|
+
mappings.each do |from, _|
|
|
1287
1641
|
from = event_model(from).symbol
|
|
1288
|
-
to = if to
|
|
1289
|
-
Array[*to].map do |ev|
|
|
1290
|
-
model = event_model(ev)
|
|
1291
|
-
raise ArgumentError, "trying to signal #{ev} which is not controlable" unless model.controlable?
|
|
1292
|
-
model.symbol
|
|
1293
|
-
end
|
|
1294
|
-
else; []
|
|
1295
|
-
end
|
|
1296
|
-
|
|
1297
|
-
signal_sets[from].merge to.to_value_set
|
|
1298
|
-
update_terminal_flag
|
|
1299
|
-
|
|
1300
1642
|
if user_handler
|
|
1301
1643
|
method_name = "event_handler_#{from}_#{Object.address_from_id(user_handler.object_id).to_s(16)}"
|
|
1302
1644
|
define_method(method_name, &user_handler)
|
|
@@ -1329,8 +1671,17 @@ module Roby
|
|
|
1329
1671
|
# See also Task#forward and EventGenerator#forward.
|
|
1330
1672
|
def self.forward(mappings)
|
|
1331
1673
|
mappings.each do |from, to|
|
|
1332
|
-
from
|
|
1333
|
-
|
|
1674
|
+
from = event_model(from).symbol
|
|
1675
|
+
targets = Array[*to].map { |ev| event_model(ev).symbol }
|
|
1676
|
+
|
|
1677
|
+
if event_model(from).terminal?
|
|
1678
|
+
non_terminal = targets.find_all { |name| !event_model(name).terminal? }
|
|
1679
|
+
if !non_terminal.empty?
|
|
1680
|
+
raise ArgumentError, "trying to establish a forwarding relation from the terminal event #{from} to the non-terminal event(s) #{targets}"
|
|
1681
|
+
end
|
|
1682
|
+
end
|
|
1683
|
+
|
|
1684
|
+
forwarding_sets[from].merge targets.to_value_set
|
|
1334
1685
|
end
|
|
1335
1686
|
update_terminal_flag
|
|
1336
1687
|
end
|
|
@@ -1341,7 +1692,7 @@ module Roby
|
|
|
1341
1692
|
end
|
|
1342
1693
|
|
|
1343
1694
|
def to_s # :nodoc:
|
|
1344
|
-
s = name.dup
|
|
1695
|
+
s = name.dup + arguments.to_s
|
|
1345
1696
|
id = owners.map do |owner|
|
|
1346
1697
|
next if owner == Roby::Distributed
|
|
1347
1698
|
sibling = remote_siblings[owner]
|
|
@@ -1353,17 +1704,22 @@ module Roby
|
|
|
1353
1704
|
s
|
|
1354
1705
|
end
|
|
1355
1706
|
|
|
1356
|
-
def pretty_print(pp) # :nodoc:
|
|
1357
|
-
pp.text "#{
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1707
|
+
def pretty_print(pp, with_owners = true) # :nodoc:
|
|
1708
|
+
pp.text "#{model.name}:0x#{self.address.to_s(16)}"
|
|
1709
|
+
if with_owners
|
|
1710
|
+
pp.breakable
|
|
1711
|
+
pp.nest(2) do
|
|
1712
|
+
pp.text " owners: "
|
|
1713
|
+
pp.seplist(owners) { |r| pp.text r.to_s }
|
|
1714
|
+
pp.breakable
|
|
1362
1715
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1716
|
+
pp.text "arguments: "
|
|
1717
|
+
arguments.pretty_print(pp)
|
|
1718
|
+
end
|
|
1719
|
+
else
|
|
1720
|
+
pp.text " "
|
|
1721
|
+
arguments.pretty_print(pp)
|
|
1722
|
+
end
|
|
1367
1723
|
end
|
|
1368
1724
|
|
|
1369
1725
|
# True if this task is a null task. See NullTask.
|
|
@@ -1417,7 +1773,7 @@ module Roby
|
|
|
1417
1773
|
def fullfills?(models, args = {})
|
|
1418
1774
|
if models.kind_of?(Task)
|
|
1419
1775
|
klass, args =
|
|
1420
|
-
models.
|
|
1776
|
+
models.model,
|
|
1421
1777
|
models.meaningful_arguments
|
|
1422
1778
|
models = [klass]
|
|
1423
1779
|
else
|
|
@@ -1429,7 +1785,7 @@ module Roby
|
|
|
1429
1785
|
|
|
1430
1786
|
# Check the arguments that are required by the model
|
|
1431
1787
|
for tag in models
|
|
1432
|
-
|
|
1788
|
+
if !self_model.has_ancestor?(tag)
|
|
1433
1789
|
return false
|
|
1434
1790
|
end
|
|
1435
1791
|
|
|
@@ -1449,6 +1805,25 @@ module Roby
|
|
|
1449
1805
|
true
|
|
1450
1806
|
end
|
|
1451
1807
|
|
|
1808
|
+
# True if +self+ can be used to replace +target+
|
|
1809
|
+
def can_replace?(target)
|
|
1810
|
+
fullfills?(*target.fullfilled_model)
|
|
1811
|
+
end
|
|
1812
|
+
|
|
1813
|
+
def can_merge?(target)
|
|
1814
|
+
target_model = target.fullfilled_model
|
|
1815
|
+
if !fullfills?(target_model.first)
|
|
1816
|
+
return false
|
|
1817
|
+
end
|
|
1818
|
+
|
|
1819
|
+
target_model.last.each do |key, val|
|
|
1820
|
+
if arguments.has_key?(key) && arguments[key] != val
|
|
1821
|
+
return false
|
|
1822
|
+
end
|
|
1823
|
+
end
|
|
1824
|
+
true
|
|
1825
|
+
end
|
|
1826
|
+
|
|
1452
1827
|
include ExceptionHandlingObject
|
|
1453
1828
|
inherited_enumerable('exception_handler', 'exception_handlers') { Array.new }
|
|
1454
1829
|
|
|
@@ -1457,9 +1832,10 @@ module Roby
|
|
|
1457
1832
|
|
|
1458
1833
|
@@exception_handler_id = 0
|
|
1459
1834
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
#
|
|
1835
|
+
##
|
|
1836
|
+
# :call-seq:
|
|
1837
|
+
# on_exception(exception_class, ...) { |task, exception_object| ... }
|
|
1838
|
+
#
|
|
1463
1839
|
# Defines an exception handler. matcher === exception_object is used to
|
|
1464
1840
|
# determine if the handler should be called when +exception_object+ has
|
|
1465
1841
|
# been fired. The first matching handler is called. Call #pass_exception to pass
|
|
@@ -1576,8 +1952,8 @@ module Roby
|
|
|
1576
1952
|
singleton_class.class_eval do
|
|
1577
1953
|
setup_poll_method(block)
|
|
1578
1954
|
end
|
|
1579
|
-
|
|
1580
|
-
|
|
1955
|
+
on(:start) { |ev| @poll_handler_id = plan.engine.add_propagation_handler(method(:poll)) }
|
|
1956
|
+
on(:stop) { |ev| plan.engine.remove_propagation_handler(@poll_handler_id) }
|
|
1581
1957
|
end
|
|
1582
1958
|
end
|
|
1583
1959
|
|
|
@@ -1617,7 +1993,7 @@ module Roby
|
|
|
1617
1993
|
start_event.call
|
|
1618
1994
|
end
|
|
1619
1995
|
on :start do
|
|
1620
|
-
success_event.
|
|
1996
|
+
success_event.forward_to_once event(:success)
|
|
1621
1997
|
success_event.if_unreachable(true) do
|
|
1622
1998
|
emit :failed if executable?
|
|
1623
1999
|
end
|
|
@@ -1648,5 +2024,3 @@ module Roby
|
|
|
1648
2024
|
|
|
1649
2025
|
end
|
|
1650
2026
|
|
|
1651
|
-
require 'roby/task-operations'
|
|
1652
|
-
|