class Syskit::RobyApp::UnmanagedProcess

A class API-compatible with Orocos::Process that represents tasks that are not started by the Syskit instance

An UnmanagedProcess can basically be in three states, which are reflected by three threads

{#monitor_thread} is started when all tasks have been resolved in {#resolve_all_tasks}. It verifies that the tasks are still reachable. The thread returns when it is not the case.

Whether the process is stil in a good state or not should be tested with {#dead?}. {#verify_threads_state} verifies that the threads themselves did not terminate with an exception (and throw the exception).

Attributes

deployed_tasks[R]

The set of deployed tasks

@return [{String=>TaskContext}] mapping from the deployed task name as

defined in {model} to the actual {Orocos::TaskContext}
host_id[R]

The host on which this process' tasks run

@return [String]

monitor_thread[R]

@api private

The thread that monitors the tasks availability

It is spawned the first time {#wait_running} returns true

name_service[R]

The name service object which should be used to resolve the tasks

pid[R]

The PID of the process in which the tasks run

This is always Process.pid as ruby tasks are instanciated inside the ruby process

@return [Integer]

process_manager[R]

The {UnmanagedTasksManager} object which created this

If non-nil, the object's dead_deployment will be called when self is stopped

@return [#dead_deployment,nil]

Public Class Methods

new(process_manager, name, model, host_id: 'unmanaged_process') click to toggle source

Creates a new object managing the tasks that represent a single unmanaged process

@param [nil,#dead_deployment] #process_manager the process manager

which created this process. If non-nil, its #dead_deployment method
will be called when {stop} is called

@param [String] name the process name @param [OroGen::Spec::Deployment] model the deployment model @param [String] #host_id a string identifying the place where the

process is expected to be running
Calls superclass method
# File lib/syskit/roby_app/unmanaged_process.rb, line 78
def initialize(process_manager, name, model, host_id: 'unmanaged_process')
    @process_manager = process_manager
    @deployed_tasks = nil
    @name_service = process_manager.name_service
    @host_id = host_id
    @quitting = Concurrent::Event.new
    super(name, model)
end

Public Instance Methods

alive?() click to toggle source

True if the process is running. This is an alias for running?

# File lib/syskit/roby_app/unmanaged_process.rb, line 197
def alive?; !dead? end
dead?() click to toggle source

Returns true if the process died

# File lib/syskit/roby_app/unmanaged_process.rb, line 187
def dead?
    if monitor_thread
        return !monitor_thread.alive?
    else quitting?
    end
end
join() click to toggle source
# File lib/syskit/roby_app/unmanaged_process.rb, line 201
def join
    raise NotImplementedError, "UnmanagedProcess#join is not implemented"
end
kill(wait = false) click to toggle source

“Kill” this process

It shuts down the tasks that are part of it

# File lib/syskit/roby_app/unmanaged_process.rb, line 157
def kill(wait = false)
    # Announce we're quitting to #monitor_thread. It's used in
    # #dead? directly if there is no monitoring thread
    @quitting.set 
end
monitor(period: 0.1) click to toggle source

@api private

Implementation of the monitor thread, i.e. the thread that will detect if the deployment disappears

@param [Float] period polling period in seconds

# File lib/syskit/roby_app/unmanaged_process.rb, line 169
def monitor(period: 0.1)
    while !quitting?
        deployed_tasks.each_value do |task|
            begin task.ping
            rescue Orocos::ComError
                return
            end
        end
        sleep period
    end
end
on_localhost?() click to toggle source

Whether the tasks in this process are running on the same machine than the ruby process

This is always true as ruby tasks are instanciated inside the ruby process

@return [Boolean]

# File lib/syskit/roby_app/unmanaged_process.rb, line 49
def on_localhost?; host_id == 'localhost' end
quitting?() click to toggle source

Whether {#kill} requested for {#monitor_thread} to quit

# File lib/syskit/roby_app/unmanaged_process.rb, line 182
def quitting?
    @quitting.set?
end
ready?() click to toggle source

Returns true if the tasks have been successfully discovered

# File lib/syskit/roby_app/unmanaged_process.rb, line 195
def ready?; !!deployed_tasks end
resolve_all_tasks(cache = Hash.new) click to toggle source
# File lib/syskit/roby_app/unmanaged_process.rb, line 110
def resolve_all_tasks(cache = Hash.new)
    resolved = model.task_activities.map do |t|
        [t.name, (cache[t.name] ||= name_service.get(t.name))]
    end
    @deployed_tasks = Hash[resolved]
    @monitor_thread = Thread.new do
        monitor
    end
    return @deployed_tasks
rescue Orocos::NotFound, Orocos::ComError => e
    if Time.now - @last_warning > 5
        Syskit.warn "waiting for unmanaged task: #{e}"
        @last_warning = Time.now
    end
    nil
end
running?() click to toggle source

True if the process is running. This is an alias for alive?

# File lib/syskit/roby_app/unmanaged_process.rb, line 199
def running?; alive? end
spawn(options = Hash.new) click to toggle source

“Starts” this process

It spawns a thread that returns once the task got resolved

@return [void]

# File lib/syskit/roby_app/unmanaged_process.rb, line 92
def spawn(options = Hash.new)
    @spawn_start = Time.now
    @last_warning = Time.now
    @deployed_tasks = nil
end
task(task_name) click to toggle source

Returns the component object for the given name

@raise [RuntimeError] if the process is not running yet @raise [ArgumentError] if the name is not the name of a task on

self
# File lib/syskit/roby_app/unmanaged_process.rb, line 132
def task(task_name)
    if !deployed_tasks
        raise RuntimeError, "process not running yet"
    elsif task = deployed_tasks[task_name]
        task
    else
        raise ArgumentError, "#{task_name} is not a task of #{self}"
    end
end
terminate_and_join_thread(thread) click to toggle source

@api private

Helper method to kill a thread

# File lib/syskit/roby_app/unmanaged_process.rb, line 145
def terminate_and_join_thread(thread)
    return if !thread.alive?
    thread.raise TerminateThread
    begin
        thread.join
    rescue TerminateThread
    end
end
verify_threads_state() click to toggle source

Verifies that the monitor thread is alive and well, or that the process either terminated or is not spawned yet

If the monitor thread terminated unexpectedly, it will raise the exception that terminated it, or a RuntimeError if no exceptions have been raised (which should not be possible)

# File lib/syskit/roby_app/unmanaged_process.rb, line 104
def verify_threads_state
    if monitor_thread && !monitor_thread.alive?
        monitor_thread.join
    end
end