Class: Syskit::TaskContext

Inherits:
Component show all
Extended by:
Logger::Hierarchy, Models::TaskContext
Includes:
Logger::Hierarchy
Defined in:
lib/syskit/task_context.rb

Overview

In the orocos/rtt, a task context is what is usually called a component.

Subclasses of TaskContext represent these components in Roby plans, an TaskContext instances may be associated with a Deployment task, that represent the underlying deployment process. The link between a task context and its deployment is usually represented by an executed_by relation.

The task configuration step is managed as follows:

  • all tasks start with executable? and setup? returning false

  • the engine will call #setup to configure the task if it is in the main plan. If the actual orocos task was already setup, #setup will actually do nothing. At this stage, executable? is still false

  • executable? will be true only if the task is configured and all static inputs are connected.

Direct Known Subclasses

ROS::Node, RubyTaskContext

Defined Under Namespace

Modules: Proxying Classes: Aborted, Interrupt, PropertiesUpdated, Start, Stop

Constant Summary collapse

D_SAME_PROCESS =

Value returned by TaskContext#distance_to when the tasks are in the same process

Orocos::OutputPort::D_SAME_PROCESS
D_SAME_HOST =

Value returned by TaskContext#distance_to when the tasks are in different processes, but on the same machine

Orocos::OutputPort::D_SAME_HOST
D_DIFFERENT_HOSTS =

Value returned by TaskContext#distance_to when the tasks are in different processes localized on different machines

Orocos::OutputPort::D_DIFFERENT_HOSTS

Constants included from Models::Component

Models::Component::PROVIDES_ARGUMENTS

Instance Attribute Summary collapse

Attributes included from Models::TaskContext

#configuration_manager, #extension_file

Attributes included from Models::Component

#concrete_model

Attributes inherited from Component

#dynamics, #required_host, #requirements

Task Arguments collapse

Task Events collapse

Instance Method Summary collapse

Methods included from Models::TaskContext

all_state_event, apply_block, clear_registration_as_constant, define_from_orogen, each_event_port, each_state_event, make_state_events, merge_service_model, needs_stub?, new_submodel, root_model, setup_submodel, state_events, worstcase_processing_time

Methods included from Models::OrogenBase

#find_model_by_orogen, #find_model_from_orogen_name, #has_model_for?, #model_for

Methods included from Models::PortAccess

#each_input_port, #each_output_port, #each_port, #find_input_port, #find_output_port, #find_port, #has_dynamic_input_port?, #has_dynamic_output_port?, #has_input_port?, #has_output_port?, #has_port?, #port_by_name

Methods included from Models::Component

#all_data_service, #all_dynamic_service, #all_stub_module, #apply_missing_dynamic_services_from, #as, #as_plan, #bind, #clear_model, #component_model?, #compute_port_mappings, #concrete_model?, #connected?, #create_dynamic_instantiation_context, #create_private_specialization, #create_proxy_task, #create_proxy_task_model, #data_service, #data_services, #deregister_placeholder_model, #deregister_submodels, #driver_for, #dynamic_service, #dynamic_services, #each_com_bus_driver_service, #each_data_service, #each_dynamic_service, #each_input_port, #each_master_driver_service, #each_output_port, #each_port, #each_required_dynamic_service, #each_required_model, #each_root_data_service, #each_slave_data_service, #each_stub_module, #ensure_model_is_specialized, #find_all_data_services_from_type, #find_data_service_from_type, #find_directional_port_mapping, #find_input_port, #find_matching_service, #find_output_port, #find_placeholder_model, #find_port, #fullfills?, #if_already_present, #implicit_fullfilled_model, #instanciate, #merge_service_model, #method_missing, #needs_stub?, #placeholder?, #port_mappings_for, #port_mappings_for_task, #prefer_deployed_tasks, #prepare_stub, #private_specialization=, #private_specialization?, #promote_data_service, #promote_dynamic_service, #provides, #provides_dynamic, #proxy_task_model, #register_placeholder_model, #require_dynamic_service, #resolve, #selected_for, #self_port?, #self_port_to_component_port, #specialization_counter, #specialize, #stub, #stub_module, #supermodel, #to_component_model, #try_bind, #try_resolve, #use_conf, #use_deployments, #with_arguments, #with_conf, #with_dynamic_service

Methods included from DataService

#using_data_service?

Methods included from Models::Base

#dependency_injection_names, #pretty_print, #short_name, #to_instance_requirements, #to_s

Methods inherited from Component

#added_dynamic_service, #added_input_port_connection, #added_output_port_connection, #adding_input_port_connection, #adding_output_port_connection, #as, #bind, #concrete_model, #connect_to, #data_accessor, #data_reader, #data_writer, #dependency_context, #duplicate_missing_services_from, #each_data_service, #each_dynamic_service, #each_fullfilled_model, #each_required_dynamic_service, #find_data_service, #find_data_service_from_type, #has_data_service?, #initialize_copy, #meets_configurationg_precedence_constraints?, #placeholder?, #removed_input_port_connection, #removed_output_port_connection, #removing_input_port_connection, #removing_output_port_connection, #require_dynamic_service, #self_port_to_actual_port, #self_port_to_component_port, #setting_up?, #setup, #setup=, #should_configure_after, #specialize, #specialized_model?, #start_only_when_connected?, #to_instance_requirements, #update_requirements

Methods included from PortAccess

#each_input_port, #each_output_port, #each_port, #find_input_port, #find_output_port, #find_port, #has_input_port?, #has_output_port?, #has_port?

Constructor Details

#initialize(orogen_model: nil, **arguments) ⇒ TaskContext

Returns a new instance of TaskContext



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/syskit/task_context.rb', line 95

def initialize(orogen_model: nil, **arguments)
    super(**arguments)

    @orogen_model   = orogen_model ||
        Orocos::Spec::TaskDeployment.new(nil, model.orogen_model)

    properties = Hash.new
    property_overrides = Hash.new
    self.model.orogen_model.each_property do |p|
        type = Roby.app.default_loader.intermediate_type_for(p.type)
        properties[p.name] = LiveProperty.new(self, p.name, type)
        property_overrides[p.name] = Property.new(p.name, type)
    end
    @properties = Properties.new(self, properties)
    @property_overrides = Properties.new(self, property_overrides)

    @current_property_commit = nil

    @setup = false
    @ready_to_start = false
    @required_host = nil
    # This is initalized to one as we known that {#setup} will
    # perform a property update
    @has_pending_property_updates = true
end

Instance Attribute Details

#last_orogen_stateObject (readonly)

The last state before we went to orogen_state



52
53
54
# File 'lib/syskit/task_context.rb', line 52

def last_orogen_state
  @last_orogen_state
end

#orocos_taskObject (readonly)

Orocos::TaskContext,Orocos::ROS::Node

the underlying remote task

context object. It is set only when the task context's deployment is running



45
46
47
# File 'lib/syskit/task_context.rb', line 45

def orocos_task
  @orocos_task
end

#orogen_modelObject

Orocos::Generation::TaskDeployment

the model of this deployment



47
48
49
# File 'lib/syskit/task_context.rb', line 47

def orogen_model
  @orogen_model
end

#orogen_stateObject (readonly)

The current state for the orogen task. It is a symbol that represents the state name (i.e. :RUNTIME_ERROR, :RUNNING, …)



50
51
52
# File 'lib/syskit/task_context.rb', line 50

def orogen_state
  @orogen_state
end

#propertiesObject (readonly)

Accessor for the task's properties

Examples:

write a property named 'latency'

task.properties.latency = 20

read the syskit-side value of the latency property

task.properties.latency # => 20

update a complex type

task.properties.position do |p|
   p.x = 10
   p.y = 20
   p.z = 30
   p
end


291
292
293
# File 'lib/syskit/task_context.rb', line 291

def properties
  @properties
end

#property_overridesObject (readonly)

Accessor for overrides of the configuration values

This is an accessor that works akin to #properties. It is used to set values that will override the values in the configuration files at #configure time

The expected configuration can later be restored with #property_overrides



303
304
305
# File 'lib/syskit/task_context.rb', line 303

def property_overrides
  @property_overrides
end

#r tid(tid) ⇒ Integer

Beware, the thread might be on a remote machine !

Returns:

  • (Integer)

    The thread ID of the thread running this task



78
79
80
# File 'lib/syskit/task_context.rb', line 78

def tid
    orocos_task.tid
end

#state_readerOrocos::TaskContext::StateReader (readonly)

The state reader object used to get state updates from the task

Returns:

  • (Orocos::TaskContext::StateReader)


487
488
489
# File 'lib/syskit/task_context.rb', line 487

def state_reader
  @state_reader
end

Instance Method Details

#aborted?Boolean

Returns:

  • (Boolean)


969
970
971
972
973
974
975
976
977
978
979
# File 'lib/syskit/task_context.rb', line 969

event :aborted, terminal: true do |context|
    if execution_agent && execution_agent.running? && !execution_agent.finishing?
        aborted_event.achieve_asynchronously(description: "aborting #{self}") do
            begin orocos_task.stop(false)
            rescue Exception
            end
        end
    else
        aborted_event.emit
    end
end

#aborted_eventEventGenerator

Returns:

  • (EventGenerator)


969
970
971
972
973
974
975
976
977
978
979
# File 'lib/syskit/task_context.rb', line 969

event :aborted, terminal: true do |context|
    if execution_agent && execution_agent.running? && !execution_agent.finishing?
        aborted_event.achieve_asynchronously(description: "aborting #{self}") do
            begin orocos_task.stop(false)
            rescue Exception
            end
        end
    else
        aborted_event.emit
    end
end

#added_sink(sink, policy) ⇒ Object



1173
1174
1175
1176
# File 'lib/syskit/task_context.rb', line 1173

def added_sink(sink, policy)
    super
    relation_graph_for(Flows::DataFlow).modified_tasks << self
end

#apply_configuration(config_type) ⇒ Object

Applies the values stored in config_type to the task properties.

It is assumed that config_type responds to each, and that the provided each method yields (name, value) pairs. These pairs are then used to call component.name=value to set the values on the component



1058
1059
1060
1061
1062
1063
1064
1065
1066
# File 'lib/syskit/task_context.rb', line 1058

def apply_configuration(config_type)
    config_type.each do |name, value|
        if has_property?(name)
            property(name).write(value)
        else
            ::Robot.warn "ignoring field #{name} in configuration of #{orocos_name} (#{model.name})"
        end
    end
end

#can_be_deployed_by?(task) ⇒ Boolean

Tests whether a task can be used as-is to deploy this

It is mostly the same as #can_merge?, while taking into account e.g. that some operations done during merging will require the component to do a reconfiguration cycle

Parameters:

Returns:

  • (Boolean)


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/syskit/task_context.rb', line 210

def can_be_deployed_by?(task)
    # NOTE: in the two tests below, we use the fact that
    # {#can_merge?} (and therefore {Component#can_be_deployed_by?})
    # already checked that services that have the same name in task
    # and self are actually of identical definition.

    return false if !super

    # First check if there are services that need to be removed.
    # Syskit doesn't support that, so for those we cannot deploy
    # using 'task'
    task.each_required_dynamic_service do |srv|
        if srv.model.remove_when_unused? && !find_data_service(srv.name)
            return false
        end
    end

    # Now check for new services that would require reconfiguration
    # when added. Unlike with remove_when_unused, if 'task' is not
    # setup, we can add the new data services to 'task' and
    # therefore ignore the differences
    return true if !task.setup?

    each_required_dynamic_service do |srv|
        if srv.model.addition_requires_reconfiguration? && !task.find_data_service(srv.name)
            return false
        end
    end

    true
end

#can_finalize?Boolean

Whether the task should be kept in plan

Returns:

  • (Boolean)


137
138
139
140
141
# File 'lib/syskit/task_context.rb', line 137

def can_finalize?
    super &&
        (!(promise = @current_property_commit) ||
           promise.complete?)
end

#can_merge?(other_task) ⇒ Boolean

Verifies if a task could be replaced by this one

false otherwise

Returns:

  • (Boolean)

    true if #merge(other_task) can be called and



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/syskit/task_context.rb', line 191

def can_merge?(other_task) # :nodoc:
    return if !super

    # Verify the host constraints (i.e. can't merge other_task in
    # +self+ if both have constraints on which host they should run,
    # and that constraint does not match)
    result = other_task.respond_to?(:required_host) &&
        (!required_host || !other_task.required_host ||
        required_host == other_task.required_host)

    if !result
        NetworkGeneration.debug { "cannot merge #{other_task} in #{self}: different host constraints" }
        false
    else
        true
    end
end

#clean_dynamic_port_connections(port_names) ⇒ Object

Remove connections manually to the dynamic ports

This is called after orocos_task.cleanup, as a task's cleanupHook is supposed to delete all dynamic ports (and therefore disconnect them)



616
617
618
619
620
621
622
623
624
# File 'lib/syskit/task_context.rb', line 616

def clean_dynamic_port_connections(port_names)
    to_remove = Hash.new
    to_remove.merge!(dynamic_input_port_connections(port_names))
    to_remove.merge!(dynamic_output_port_connections(port_names))
    relation_graph_for(Flows::DataFlow).modified_tasks << self
    to_remove.each do |(source_task, sink_task), connections|
        ActualDataFlow.remove_connections(source_task, sink_task, connections)
    end
end

#clear_property_overridesObject

Clears the currently defined overrides, and restores the original property values



1043
1044
1045
1046
1047
1048
1049
1050
# File 'lib/syskit/task_context.rb', line 1043

def clear_property_overrides
    property_overrides.clear_values
    property_overrides.each do |property_override|
        if value = property_override.remote_value
            properties[property_override.name].write(value)
        end
    end
end

#commit_properties(promise = self.promise(description: "promise:#{self}#commit_properties")) ⇒ Roby::Promise

Create a promise that will apply the properties stored Syskit-side to the underlying component

This usually does not need to be called, as Syskit queues a property update at the component configuration, and whenever a property gets updated

Returns:

  • (Roby::Promise)


391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/syskit/task_context.rb', line 391

def commit_properties(promise = self.promise(description: "promise:#{self}#commit_properties"))
    promise.on_success(description: "#{self}#commit_properties#init") do
        if finalized? || garbage? || finishing? || finished?
            []
        else
            # NOTE: {#queue_property_update_if_needed}, is a
            # *delayed* property commit. It attempts at doing one
            # batched write for many writes from Property#write.
            #
            # This works because the property-snapshot step (this
            # step) is done within the event loop.

            # Register this as the active property commit
            # for the benefit of {#handle_state_change} and
            # synchronizing with the task stop
            @current_property_commit = promise

            # Reset to false (allowing commit queueing from
            # Property#write) only if the task is starting and/or
            # running. This is because we explicitely commit
            # properties within the setup step, and within the
            # task's start event.
            @has_pending_property_updates = !(starting? || running?)

            each_property.map do |p|
                if p.needs_commit?
                    [p, p.value.dup]
                end
            end.compact
        end
    end
    promise.then(description: "#{self}#commit_properties#write") do |properties|
        properties.map do |p, p_value|
            begin
                p.remote_property.write(p_value)
                [Time.now, p, nil]
            rescue ::Exception => e
                [Time.now, p, e]
            end
        end.compact
    end.on_success(description: "#{self}#commit_properties#update_log") do |result|
        result.map do |timestamp, property, error|
            if error
                execution_engine.add_error(PropertyUpdateError.new(error, property))
            else
                property.update_remote_value(property.value)
                property.update_log(timestamp)
                property
            end
        end.compact
    end

    @has_pending_property_updates = true
    promise
end

#commit_properties_if_needed(*args) ⇒ Roby::Promise, Roby::Promise::Null

Create a promise that will apply the properties stored Syskit-side to the underlying component, but only if the underlying task would have a use for it (e.g. it is running or pending)

It returns a null promise otherwise.

Examples:

apply the next property updates and emit the event once

the properties have been applied, but do not do it if the
underlying task is finished

updated_configuration_event.achieve_asynchronously(
    my_child.commit_properties_if_needed)
# Do the property updates

Returns:

  • (Roby::Promise, Roby::Promise::Null)

See Also:



375
376
377
378
379
380
381
# File 'lib/syskit/task_context.rb', line 375

def commit_properties_if_needed(*args)
    if would_use_property_update?
        commit_properties(*args)
    else
        Roby::Promise.null
    end
end

#confObject

The task's configuration, as a list of registered configurations for the underlying task context

For instance ['default', 'left_camera'] will apply the 'default' section of config/orogen/orogen_project::TaskClassName.yml and then override with the 'left_camera' section of the same file



37
# File 'lib/syskit/task_context.rb', line 37

argument :conf, :default => ['default']

#conf=Object

The task's configuration, as a list of registered configurations for the underlying task context

For instance ['default', 'left_camera'] will apply the 'default' section of config/orogen/orogen_project::TaskClassName.yml and then override with the 'left_camera' section of the same file



37
# File 'lib/syskit/task_context.rb', line 37

argument :conf, :default => ['default']

#configureObject

Default implementation of the configure method.

This default implementation takes its configuration from State.config.task_name, where task_name is the CORBA task name (i.e. the global name of the task).

It then sets the task properties using the values found there



1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
# File 'lib/syskit/task_context.rb', line 1004

def configure
    # First, set configuration from the configuration files
    # Note: it can only set properties
    if model.configuration_manager.apply(self, override: true)
        info "applied configuration #{conf} to #{orocos_task.name}"
    end

    # Then set configuration stored in Syskit.conf
    if Syskit.conf.orocos.send("#{orocos_name}?")
        config = Syskit.conf.orocos.send(orocos_name)
        apply_configuration(config)
    end

    # Then set per-device configuration options
    if respond_to?(:each_master_device)
        each_master_device do |device|
            if device.configuration
                apply_configuration(device.configuration)
            elsif device.configuration_block
                device.configuration_block.call(self)
            end
        end
    end

    property_overrides.each do |property_override|
        if property_override.has_value?
            actual_property = properties[property_override.name]
            if actual_property.has_value?
                property_override.update_remote_value(actual_property.read)
            end
            actual_property.write(property_override.read)
        end
    end

    super if defined? super
end

#create_fresh_copyObject

:nodoc:



121
122
123
124
125
126
# File 'lib/syskit/task_context.rb', line 121

def create_fresh_copy # :nodoc:
    new_task = super
    new_task.orocos_task  = orocos_task
    new_task.orogen_model = orogen_model
    new_task
end

#deployment_hintsObject



260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/syskit/task_context.rb', line 260

def deployment_hints
    hints = requirements.deployment_hints.to_set.dup
    return hints if !hints.empty?

    if respond_to?(:each_master_device)
        each_master_device do |dev|
            hints |= dev.requirements.deployment_hints.to_set
        end
    end
    return hints if !hints.empty?

    super
end

#distance_to(other) ⇒ Object

Returns a value that represents how the two task contexts are far from each other. The possible return values are:

nil

one or both of the tasks are not deployed

D_SAME_PROCESS

both tasks are in the same process

D_SAME_HOST

both tasks are in different processes, but on the same machine

D_DIFFERENT_HOSTS

both tasks are in different processes localized on different machines



182
183
184
185
# File 'lib/syskit/task_context.rb', line 182

def distance_to(other)
    return if !execution_agent || !other.execution_agent
    execution_agent.distance_to(other.execution_agent)
end

#distance_to_syskitObject

How “far” this process is from the Syskit process

Returns:



156
157
158
# File 'lib/syskit/task_context.rb', line 156

def distance_to_syskit
    execution_agent.distance_to_syskit
end

#dynamic_input_port_connections(existing_port_names) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper for #prepare_for_setup that enumerates the inbound connections originating from a dynamic output port



630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
# File 'lib/syskit/task_context.rb', line 630

def dynamic_input_port_connections(existing_port_names)
    to_remove = Hash.new
    real_model = self.model.concrete_model
    dynamic_ports = self.model.each_input_port.find_all do |p|
        !real_model.find_input_port(p.name)
    end
    dynamic_ports = dynamic_ports.map(&:name).to_set

    dynamic_ports.each do |name|
        if existing_port_names.include?(name)
            Syskit.fatal "task #{orocos_task} did not clear #{name}, a dynamic input port, during cleanup, as it should have. Go fix it."
        end
    end

    ActualDataFlow.each_in_neighbour(orocos_task) do |source_task|
        mappings = ActualDataFlow.edge_info(source_task, orocos_task)
        to_remove[[source_task, orocos_task]] = mappings.each_key.find_all do |from_port, to_port|
            dynamic_ports.include?(to_port)
        end
    end
    to_remove
end

#dynamic_output_port_connections(existing_port_names) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper for #prepare_for_setup that enumerates the outbound connections originating from a dynamic output port



657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
# File 'lib/syskit/task_context.rb', line 657

def dynamic_output_port_connections(existing_port_names)
    to_remove = Hash.new
    real_model = self.model.concrete_model
    dynamic_ports = self.model.each_output_port.find_all do |p|
        !real_model.find_output_port(p.name)
    end
    dynamic_ports = dynamic_ports.map(&:name).to_set

    dynamic_ports.each do |name|
        if existing_port_names.include?(name)
            Syskit.fatal "task #{orocos_task} did not clear #{name}, a dynamic output port, during cleanup, as it should have. Go fix it."
        end
    end

    ActualDataFlow.each_out_neighbour(orocos_task) do |sink_task|
        mappings = ActualDataFlow.edge_info(orocos_task, sink_task)
        to_remove[[orocos_task, sink_task]] = mappings.each_key.find_all do |from_port, to_port|
            dynamic_ports.include?(from_port)
        end
    end
    to_remove
end

#each_property(&block) ⇒ Object

Enumerate this task's known properties



306
307
308
# File 'lib/syskit/task_context.rb', line 306

def each_property(&block)
    properties.each(&block)
end

#exception_eventObject

Returns the exception error event object for this task. This event gets emitted whenever the component goes into an exception state.



# File 'lib/syskit/task_context.rb', line 934

#executable?Boolean

Whether this task context can be started

Under syskit, this can happen only if the task has been setup and all its inputs are connected

Returns:

  • (Boolean)


132
133
134
# File 'lib/syskit/task_context.rb', line 132

def executable?
    @executable || (@ready_to_start && super)
end

#fatal_error_eventObject

Returns the fatal error event object for this task. This event gets emitted whenever the component goes into a fatal error state.

This leads to the component emitting both :failed and :stop



947
# File 'lib/syskit/task_context.rb', line 947

forward :start => :running

#find_property(name) ⇒ Object

Resolves a property by name

Parameters:

  • name (String)


331
332
333
# File 'lib/syskit/task_context.rb', line 331

def find_property(name)
    properties[name.to_str]
end

#find_through_method_missing(m, args) ⇒ Object



1190
1191
1192
1193
# File 'lib/syskit/task_context.rb', line 1190

def find_through_method_missing(m, args)
    MetaRuby::DSLs.find_through_method_missing(
        self, m, args, '_property' => :find_property) || super
end

#handle_state_changesObject

Handle a state transition by emitting the relevant events



809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
# File 'lib/syskit/task_context.rb', line 809

def handle_state_changes # :nodoc:
    # If we are starting, we should ignore all states until a
    # runtime state is found
    if !@got_running_state
        if orocos_task.runtime_state?(orogen_state)
            @got_running_state = true
            @last_terminal_state = nil
            start_event.emit
        else
            return
        end
    end

    if orocos_task.runtime_state?(orogen_state)
        if last_orogen_state && orocos_task.error_state?(last_orogen_state)
            running_event.emit
        elsif @last_terminal_state
            fatal "#{self} reports state #{orogen_state} after having reported a terminal state (#{@last_terminal_state}). Syskit will try to go on, but this should not happen."
        end
    end

    state_event =
        if orogen_state == :STOPPED
            if interrupt_event.pending?
                interrupt_event
            elsif finishing?
                stop_event
            else
                success_event
            end
        elsif orogen_state != :RUNNING
            if event_name = state_event(orogen_state)
                event(event_name)
            else
                raise ArgumentError, "#{self} reports state #{orogen_state}, but I don't have an event for this state transition"
            end
        end
    return if !state_event
    if state_event.terminal?
        # This is needed so that the first step of
        # @current_property_commit cancels the promise.
        self.finishing = true

        # If there's a pending property commit, we must wait for it
        # to finish before emitting the event
        if (promise = @current_property_commit) && !promise.complete?
            promise.add_observer do
                execution_engine.execute(type: :propagation) do
                    state_event.emit
                end
            end
        else
            state_event.emit
        end
        @last_terminal_state = orogen_state

    elsif orogen_state != :RUNNING
        state_event.emit
    end
end

#has_property?(name) ⇒ Boolean

Whether this task has a property with the given name

Returns:

  • (Boolean)


311
312
313
# File 'lib/syskit/task_context.rb', line 311

def has_property?(name)
    properties.include?(name)
end

#has_through_method_missing?(m) ⇒ Boolean

Returns:

  • (Boolean)


1186
1187
1188
1189
# File 'lib/syskit/task_context.rb', line 1186

def has_through_method_missing?(m)
    MetaRuby::DSLs.has_through_method_missing?(
        self, m, '_property' => :has_property?) || super
end

#in_process?Boolean

Whether this task runs within the Syskit process itself

Returns:

  • (Boolean)


161
162
163
# File 'lib/syskit/task_context.rb', line 161

def in_process?
    execution_agent.in_process?
end

#initialize_remote_handles(remote_handles) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize the communication with the remote task

Parameters:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/syskit/task_context.rb', line 59

def initialize_remote_handles(remote_handles)
    @orocos_task       = remote_handles.handle
    @orocos_task.model = model.orogen_model
    @state_reader      = remote_handles.state_reader

    remote_handles.default_properties.each do |p, p_value|
        syskit_p = property(p.name)
        syskit_p.remote_property = p
        syskit_p.update_remote_value(p_value)
        syskit_p.(p.)
        if !syskit_p.has_value?
            syskit_p.write(p_value)
        end
    end
end

#instanciate_dynamic_input_port(name, type, port) ⇒ Port

Adds a new port to this model based on a known dynamic port

Parameters:

  • name (String)

    the new port's name

  • port (Orocos::Spec::DynamicInputPort)

    the port model, as returned for instance by Orocos::Spec::TaskContext#find_dynamic_input_ports

Returns:

  • (Port)

    the new port



1100
1101
1102
1103
# File 'lib/syskit/task_context.rb', line 1100

def instanciate_dynamic_input_port(name, type, port)
    specialize
    model.instanciate_dynamic_input_port(name, type, port).bind(self)
end

#instanciate_dynamic_output_port(name, type, port) ⇒ Port

Adds a new port to this model based on a known dynamic port

Parameters:

  • name (String)

    the new port's name

  • port (Orocos::Spec::DynamicOutputPort)

    the port model, as returned for instance by Orocos::Spec::TaskContext#find_dynamic_output_ports

Returns:

  • (Port)

    the new port's model



1111
1112
1113
1114
# File 'lib/syskit/task_context.rb', line 1111

def instanciate_dynamic_output_port(name, type, port)
    specialize
    model.instanciate_dynamic_output_port(name, type, port).bind(self)
end

#interrupt?Boolean

Interrupts the execution of this task context

Returns:

  • (Boolean)


897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
# File 'lib/syskit/task_context.rb', line 897

event :interrupt do |context|
	        info "interrupting #{self}"

    if !orocos_task # already killed
        interrupt_event.emit
        aborted_event.emit
    elsif execution_agent && !execution_agent.finishing?
        promise = execution_engine.
            promise(description: "promise:#{self}#interrupt") do
                stop_orocos_task
            end.
            on_success(description: "#{self}#interrupt#done") do |result|
                if result == :aborted
                    interrupt_event.emit
                    aborted_event.emit
                end
            end

        interrupt_event.achieve_asynchronously(promise, emit_on_success: false)
    end
end

#interrupt_eventEventGenerator

Interrupts the execution of this task context

Returns:

  • (EventGenerator)


897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
# File 'lib/syskit/task_context.rb', line 897

event :interrupt do |context|
	        info "interrupting #{self}"

    if !orocos_task # already killed
        interrupt_event.emit
        aborted_event.emit
    elsif execution_agent && !execution_agent.finishing?
        promise = execution_engine.
            promise(description: "promise:#{self}#interrupt") do
                stop_orocos_task
            end.
            on_success(description: "#{self}#interrupt#done") do |result|
                if result == :aborted
                    interrupt_event.emit
                    aborted_event.emit
                end
            end

        interrupt_event.achieve_asynchronously(promise, emit_on_success: false)
    end
end

#kill_execution_agent_if_aloneObject



954
955
956
957
958
959
960
961
962
963
964
965
966
967
# File 'lib/syskit/task_context.rb', line 954

def kill_execution_agent_if_alone
    if execution_agent
        not_loggers = execution_agent.each_executed_task.
            find_all { |t| !Roby.app.syskit_utility_component?(t) }
        if not_loggers.size == 1
            plan.unmark_permanent_task(execution_agent)
            if execution_agent.running?
                execution_agent.stop!
                return true
            end
        end
    end
    false
end

#merge(merged_task) ⇒ void

This method returns an undefined value.

Replaces the given task by this task

Parameters:

  • merged_task (TaskContext)

    the task that should be replaced



246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/syskit/task_context.rb', line 246

def merge(merged_task)
    super
    self.required_host ||= merged_task.required_host

    if merged_task.orogen_model && !orogen_model
        self.orogen_model = merged_task.orogen_model
    end

    if merged_task.orocos_task && !orocos_task
        self.orocos_task = merged_task.orocos_task
    end
    nil
end

#needs_reconfiguration!Object

Make sure that #configure will be called on this task before it gets started

See also #setup and #needs_reconfiguration?



602
603
604
# File 'lib/syskit/task_context.rb', line 602

def needs_reconfiguration!
    execution_agent.needs_reconfiguration!(orocos_name) if execution_agent
end

#needs_reconfiguration?Boolean

If true, #configure must be called on this task before it is started. This flag is reset after #configure has been called

Returns:

  • (Boolean)


592
593
594
595
596
# File 'lib/syskit/task_context.rb', line 592

def needs_reconfiguration?
    if execution_agent
        execution_agent.needs_reconfiguration?(orocos_name)
    end
end

#on_localhost?Boolean

Whether this task runs on the same host than the Syskit process

Returns:

  • (Boolean)


166
167
168
# File 'lib/syskit/task_context.rb', line 166

def on_localhost?
    execution_agent.on_localhost?
end

#operation(name) ⇒ Object



274
275
276
# File 'lib/syskit/task_context.rb', line 274

def operation(name)
    orocos_task.operation(name)
end

#orocos_nameObject

The name of the remote task context, i.e. the name under which it can be resolved by Orocos.name_service



40
# File 'lib/syskit/task_context.rb', line 40

argument :orocos_name

#orocos_name=Object

The name of the remote task context, i.e. the name under which it can be resolved by Orocos.name_service



40
# File 'lib/syskit/task_context.rb', line 40

argument :orocos_name

#perform_setup(promise) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The actual setup operations. Component#setup is the user-facing part of the setup API, which creates the promise and sets up the setup-related bookkeeping operations



722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
# File 'lib/syskit/task_context.rb', line 722

def perform_setup(promise)
    prepare_for_setup(promise)
    # This calls #configure
    super(promise)

    properties_updated_in_configure = false
    promise.on_success(description: "#{self}#perform_setup#log_properties") do
        if self.model.needs_stub?(self)
            self.model.prepare_stub(self)
        end
        if Syskit.conf.logs.conf_logs_enabled?
            each_property do |p|
                p.log_stream = Syskit.conf.logs.log_stream_for(p)
                p.update_log
            end
        end
        properties_updated_in_configure = self.properties.each.any? { |p| p.needs_commit? }
    end
    commit_properties(promise)
    promise.then(description: "#{self}#perform_setup#orocos_task.configure") do
        state = orocos_task.rtt_state
        if properties_updated_in_configure && state != :PRE_OPERATIONAL
            info "properties have been changed within #configure, cleaning up #{self}"
            orocos_task.cleanup(false)
            state = :PRE_OPERATIONAL
        end

        if state == :PRE_OPERATIONAL
            info "setting up #{self}"
            orocos_task.configure(false)
        else
            info "#{self} was already configured"
        end
    end
end

#prepare_for_setup(promise) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Setup operations that must be performed before Component#perform_setup is called by #perform_setup



684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'lib/syskit/task_context.rb', line 684

def prepare_for_setup(promise)
    promise.then(description: "#{self}#prepare_for_setup#read_properties") do
            properties = each_property.map do |syskit_p|
                [syskit_p, syskit_p.remote_property.raw_read]
            end
            [properties, orocos_task.rtt_state]
        end.on_success(description: "#{self}#prepare_for_setup#write properties and needs_reconfiguration") do |properties, state|
            properties.each do |syskit_p, remote_value|
                syskit_p.update_remote_value(remote_value)
            end

            needs_reconfiguration = needs_reconfiguration? ||
                execution_agent.configuration_changed?(
                    orocos_name, self.conf, each_required_dynamic_service.to_set) ||
                self.properties.each.any? { |p| p.needs_commit? }

            if !needs_reconfiguration
                info "not reconfiguring #{self}: the task is already configured as required"
            end
            [needs_reconfiguration, state]
        end.then(description: "#{self}#prepare_for_setup#ensure_pre_operational") do |needs_reconfiguration, state|
            if state == :EXCEPTION
                info "reconfiguring #{self}: the task was in exception state"
                orocos_task.reset_exception(false)
                orocos_task.port_names
            elsif needs_reconfiguration && (state != :PRE_OPERATIONAL)
                info "cleaning up #{self}"
                orocos_task.cleanup(false)
                orocos_task.port_names
            end
        end.on_success(description: "#{self}#prepare_for_setup#clean_dynamic_port_connections") do |port_names|
            if port_names
                clean_dynamic_port_connections(port_names)
            end
        end
end

#properties_updated?Boolean

Event emitted when a property commit has successfully finished

Returns:

  • (Boolean)


336
# File 'lib/syskit/task_context.rb', line 336

event :properties_updated

#properties_updated_eventEventGenerator

Event emitted when a property commit has successfully finished

Returns:

  • (EventGenerator)


336
# File 'lib/syskit/task_context.rb', line 336

event :properties_updated

#property(name) ⇒ Object

Returns the syskit-side representation of the given property

Properties in Syskit are applied only at configuration time, or when #commit_properties is called



319
320
321
322
323
324
325
326
# File 'lib/syskit/task_context.rb', line 319

def property(name)
    name = name.to_s
    if p = find_property(name)
        p
    else
        raise Orocos::InterfaceObjectNotFound.new(self, name), "#{self} has no property called #{name}"
    end
end

#queue_property_update_if_neededObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Queue a remote property update if none are pending

This is used by Property on writes. Note that because of the general property update structure, all property updates happening in a single execution cycle will be committed together.



349
350
351
352
353
354
355
356
357
# File 'lib/syskit/task_context.rb', line 349

def queue_property_update_if_needed
    if !would_use_property_update?
        raise InvalidState, "attempting to queue a property update on a finished or finishing task"
    end

    if !@has_pending_property_updates
        commit_properties.execute
    end
end

#read_current_stateObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Pull all state changes that are still queued within the state reader and returns the last one

It is destructive, as it does “forget” any pending state changes currently queued.



513
514
515
516
517
518
# File 'lib/syskit/task_context.rb', line 513

def read_current_state
    while new_state = state_reader.read_new
        state = new_state
    end
    state || state_reader.read
end

#ready_for_setup?(state = nil) ⇒ Boolean

Returns true if this component needs to be setup by calling the #setup method, or if it can be used as-is

Returns:

  • (Boolean)


528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/syskit/task_context.rb', line 528

def ready_for_setup?(state = nil)
    if execution_agent.configuring?(orocos_name)
        debug { "#{self} not ready for setup: already configuring" }
        return false
    elsif !super()
        return false
    elsif !all_inputs_connected?(only_static: true)
        debug { "#{self} not ready for setup: some static ports are not connected" }
        return false
    elsif !orogen_model || !orocos_task
        debug { "#{self} not ready for setup: no orogen model or no orocos task" }
        return false
    end

    state ||= read_current_state
    configurable_state = [:STOPPED, :PRE_OPERATIONAL].include?(state) ||
        orocos_task.exception_state?(state)
    if configurable_state
        true
    else
        debug { "#{self} not ready for setup: in state #{state}, expected STOPPED, PRE_OPERATIONAL or an exception state" }
        false
    end
end

#ready_to_start!Object



566
567
568
# File 'lib/syskit/task_context.rb', line 566

def ready_to_start!
    @ready_to_start = true
end

#removed_sink(source) ⇒ Object



1181
1182
1183
1184
# File 'lib/syskit/task_context.rb', line 1181

def removed_sink(source)
    super
    relation_graph_for(Flows::DataFlow).modified_tasks << self
end

#reusable?Boolean

Tests if this task can be reused in the next deployment run

Returns:

  • (Boolean)


607
608
609
# File 'lib/syskit/task_context.rb', line 607

def reusable?
    super && (!setup? || !needs_reconfiguration?)
end

#running_eventObject

Returns the running event object for this task. This event gets emitted whenever the component goes into the Running state, either because it has just been started or because it left a runtime error state.



# File 'lib/syskit/task_context.rb', line 921

#runtime_error_eventObject

Returns the runtime error event object for this task. This event gets emitted whenever the component goes into a runtime error state.



# File 'lib/syskit/task_context.rb', line 928

#self_port_to_orocos_port(port) ⇒ Orocos::Port

Resolves the given Syskit::Port object into the actual Port object on the underlying task.

It should not be used directly. One should usually use Port#to_orocos_port instead

Returns:

  • (Orocos::Port)


1086
1087
1088
1089
1090
1091
1092
# File 'lib/syskit/task_context.rb', line 1086

def self_port_to_orocos_port(port)
    orocos_port = orocos_task.raw_port(port.name)
    if orocos_port.type != port.type
        raise UnexpectedPortType.new(port, orocos_port.type)
    end
    orocos_port
end

#setting_up!(promise) ⇒ Object

(see Component#setting_up!)_



759
760
761
762
# File 'lib/syskit/task_context.rb', line 759

def setting_up!(promise)
    super
    execution_agent.start_configuration(orocos_name)
end

#setup?Boolean

Returns true if the underlying Orocos task has been configured and can be started

The general protocol is:

if !setup? && ready_for_setup?
    setup
end

Returns:

  • (Boolean)


562
563
564
# File 'lib/syskit/task_context.rb', line 562

def setup?
    @setup
end

#setup_failed!(exception) ⇒ Object

(see Component#setup_failed!)_



765
766
767
768
# File 'lib/syskit/task_context.rb', line 765

def setup_failed!(exception)
    execution_agent.finished_configuration(orocos_name)
    super
end

#setup_successful!Object

Announces that the task is indeed setup

This is meant for internal use. Don't use it unless you know what you are doing



574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
# File 'lib/syskit/task_context.rb', line 574

def setup_successful!
    execution_agent.update_current_configuration(
        orocos_name, model, self.conf.dup, self.each_required_dynamic_service.to_set)
    execution_agent.finished_configuration(orocos_name)

    if all_inputs_connected?
        ready_to_start!
        execution_engine.scheduler.report_action "configured and all inputs connected, marking as executable", self
        Runtime.debug { "#{self} is setup and all its inputs are connected, executable? = #{executable?}" }
    else
        execution_engine.scheduler.report_action "configured, but some connections are pending", self
        Runtime.debug { "#{self} is setup but some of its inputs are not connected, executable = #{executable?}" }
    end
    super
end

#start?Boolean

Optionally configures and then start the component. The start event will be emitted when the it has successfully been configured and started.

Returns:

  • (Boolean)


775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
# File 'lib/syskit/task_context.rb', line 775

event :start do |context|
    info "starting #{to_s}"
    @last_orogen_state = nil

    if state_reader.respond_to?(:resume)
        state_reader.resume
    end

    expected_output_ports = each_concrete_output_connection.
        map { |port_name, _| port_name }
    expected_input_ports = each_concrete_input_connection.
        map { |_, _, port_name, _| port_name }
    promise = promise(description: "promise:#{self}#start")
    commit_properties(promise)
    promise.then do
        port_names = orocos_task.port_names.to_set
        # At this point, we should have already created all the dynamic
        # ports that are required ... check that
        expected_output_ports.each do |source_port|
            if !port_names.include?(source_port)
                raise Orocos::NotFound, "#{orocos_name}(#{orogen_model.name}) does not have a port named #{source_port}"
            end
        end
        expected_input_ports.each do |sink_port|
            if !port_names.include?(sink_port)
                raise Orocos::NotFound, "#{orocos_name}(#{orogen_model.name}) does not have a port named #{sink_port}"
            end
        end
        orocos_task.start(false)
    end
    start_event.achieve_asynchronously(promise, emit_on_success: false)
end

#start_eventEventGenerator

Optionally configures and then start the component. The start event will be emitted when the it has successfully been configured and started.

Returns:

  • (EventGenerator)


775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
# File 'lib/syskit/task_context.rb', line 775

event :start do |context|
    info "starting #{to_s}"
    @last_orogen_state = nil

    if state_reader.respond_to?(:resume)
        state_reader.resume
    end

    expected_output_ports = each_concrete_output_connection.
        map { |port_name, _| port_name }
    expected_input_ports = each_concrete_input_connection.
        map { |_, _, port_name, _| port_name }
    promise = promise(description: "promise:#{self}#start")
    commit_properties(promise)
    promise.then do
        port_names = orocos_task.port_names.to_set
        # At this point, we should have already created all the dynamic
        # ports that are required ... check that
        expected_output_ports.each do |source_port|
            if !port_names.include?(source_port)
                raise Orocos::NotFound, "#{orocos_name}(#{orogen_model.name}) does not have a port named #{source_port}"
            end
        end
        expected_input_ports.each do |sink_port|
            if !port_names.include?(sink_port)
                raise Orocos::NotFound, "#{orocos_name}(#{orogen_model.name}) does not have a port named #{sink_port}"
            end
        end
        orocos_task.start(false)
    end
    start_event.achieve_asynchronously(promise, emit_on_success: false)
end

#state_event(name) ⇒ Symbol

Returns the task's event name that maps to the given component state name

Returns:

  • (Symbol)


85
86
87
# File 'lib/syskit/task_context.rb', line 85

def state_event(name)
    model.find_state_event(name)
end

#stop?Boolean

Interrupts the execution of this task context

Returns:

  • (Boolean)


986
987
988
# File 'lib/syskit/task_context.rb', line 986

event :stop do |context|
    interrupt!
end

#stop_eventEventGenerator

Interrupts the execution of this task context

Returns:

  • (EventGenerator)


986
987
988
# File 'lib/syskit/task_context.rb', line 986

event :stop do |context|
    interrupt!
end

#stop_orocos_taskObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method that is called in a separate thread to stop the orocos task, taking into account some corner cases such as a dead task, or a task that raises StateTransitionFailed but stops anyways



876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
# File 'lib/syskit/task_context.rb', line 876

def stop_orocos_task
    orocos_task.stop(false)
    nil
rescue Orocos::ComError
    # We actually aborted. Notify the callback so that it emits
    # interrupt and stop
    :aborted
rescue Orocos::StateTransitionFailed
    # Use #rtt_state as it has no problem with asynchronous
    # communication, unlike the port-based state updates.
    state = orocos_task.rtt_state
    if state != :RUNNING
        Runtime.debug { "in the interrupt event, StateTransitionFailed: task.state == #{state}" }
        # Nothing to do, the poll block will finalize the task
        nil
    else
        raise
    end
end

#stub!(name = nil) ⇒ Object

Stub this task context by assigning a Orocos::RubyTaskContext to #orocos_task



1069
1070
1071
1072
1073
1074
1075
1076
1077
# File 'lib/syskit/task_context.rb', line 1069

def stub!(name = nil)
    if !name && !orocos_name
        raise ArgumentError, "orocos_task is not set on #{self}, you must provide an explicit name in #stub!"
    end
    if name
        self.orocos_name = name
    end
    self.orocos_task = Orocos::RubyTaskContext.from_orogen_model(orocos_name, model.orogen_model)
end

#tidObject



78
79
80
# File 'lib/syskit/task_context.rb', line 78

def tid
    orocos_task.tid
end

#trigger_latencyObject

Maximum time between the task is sent a trigger signal and the time it is actually triggered



91
92
93
# File 'lib/syskit/task_context.rb', line 91

def trigger_latency
    orogen_model.worstcase_trigger_latency
end

#update_orogen_stateObject

Called at each cycle to update the orogen_state attribute for this task using the values read from the state reader



491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/syskit/task_context.rb', line 491

def update_orogen_state
    @state_sample ||= state_reader.new_sample
    result, v = state_reader.read_with_result(@state_sample, false)
    if !result
        if !state_reader.connected?
            fatal "terminating #{self}, its state reader #{state_reader} is disconnected"
            aborted!
        end
        return
    elsif v
        @last_orogen_state = @orogen_state
        @orogen_state = v
    end
end

#updated_sink(sink, policy) ⇒ Object



1177
1178
1179
1180
# File 'lib/syskit/task_context.rb', line 1177

def updated_sink(sink, policy)
    super
    relation_graph_for(Flows::DataFlow).modified_tasks << self
end

#validate_orogen_state_from_rtt_stateObject

Validates that the current value in #orogen_state matches the value returned by orocos_task.rtt_state. This is called automatically if #validate_orogen_states? is set to true



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/syskit/task_context.rb', line 460

def validate_orogen_state_from_rtt_state
    orogen_state = orogen_state
    rtt_state    = orocos_task.rtt_state
    mismatch =
        case rtt_state
        when :RUNNING
            !orocos_task.runtime_state?(orogen_state)
        when :STOPPED
            orogen_state != :STOPPED
        when :RUNTIME_ERROR
            !orocos_task.error_state?(orogen_state)
        when :FATAL_ERROR
            !orocos_task.fatal_error_state?(orogen_state)
        when :EXCEPTION
            !orocos_task.exception_state?(orogen_state)
        end

    if mismatch
        Runtime.warn "state mismatch on #{self} between state=#{orogen_state} and rtt_state=#{rtt_state}"
        @orogen_state = rtt_state
        handle_state_changes
    end
end

#validate_orogen_states=(value) ⇒ Object

If true, the current state (got from the component's state port) is compared with the RTT state as reported by the task itself through a port.

This should only be used for debugging reasons, and if you know what you are doing: inconsistencies can arise because the state port is an asynchronous mean of communication while #rtt_state is synchronous



455
# File 'lib/syskit/task_context.rb', line 455

attr_predicate :validate_orogen_states, true

#validate_orogen_states?Boolean

If true, the current state (got from the component's state port) is compared with the RTT state as reported by the task itself through a port.

This should only be used for debugging reasons, and if you know what you are doing: inconsistencies can arise because the state port is an asynchronous mean of communication while #rtt_state is synchronous

Returns:

  • (Boolean)


455
# File 'lib/syskit/task_context.rb', line 455

attr_predicate :validate_orogen_states, true

#will_never_setup?(state = nil) ⇒ Boolean

Whether this task context will ever be configurable

Returns:

  • (Boolean)


521
522
523
524
# File 'lib/syskit/task_context.rb', line 521

def will_never_setup?(state = nil)
    state ||= read_current_state
    state == :FATAL_ERROR
end

#would_use_property_update?Boolean

Returns:

  • (Boolean)


338
339
340
# File 'lib/syskit/task_context.rb', line 338

def would_use_property_update?
    pending? || starting? || (running? && !finishing?)
end