Module: Roby

Extended by:
Logger::Forward, Logger::Hierarchy, ExceptionHandlingObject
Included in:
Test
Defined in:
lib/roby.rb,
lib/roby/app.rb,
lib/roby/plan.rb,
lib/roby/event.rb,
lib/roby/query.rb,
lib/roby/config.rb,
lib/roby/control.rb,
lib/roby/control.rb,
lib/roby/log/dot.rb,
lib/roby/support.rb,
lib/roby/app/rake.rb,
lib/roby/planning.rb,
lib/roby/interface.rb,
lib/roby/relations.rb,
lib/roby/exceptions.rb,
lib/roby/log/server.rb,
lib/roby/test/tools.rb,
lib/roby/log/timings.rb,
lib/roby/plan-object.rb,
lib/roby/propagation.rb,
lib/roby/state/state.rb,
lib/roby/test/common.rb,
lib/roby/thread_task.rb,
lib/roby/basic_object.rb,
lib/roby/state/events.rb,
lib/roby/transactions.rb,
lib/roby/log/chronicle.rb,
lib/roby/log/relations.rb,
lib/roby/planning/task.rb,
lib/roby/test/testcase.rb,
lib/roby/planning/loops.rb,
lib/roby/planning/model.rb,
lib/roby/standard_errors.rb,
lib/roby/task-operations.rb,
lib/roby/test/tasks/goto.rb,
lib/roby/decision_control.rb,
lib/roby/distributed/base.rb,
lib/roby/distributed/peer.rb,
lib/roby/log/event_stream.rb,
lib/roby/test/distributed.rb,
lib/roby/distributed/proxy.rb,
lib/roby/executives/simple.rb,
lib/roby/log/notifications.rb,
lib/roby/state/information.rb,
lib/roby/relations/conflicts.rb,
lib/roby/relations/influence.rb,
lib/roby/distributed/protocol.rb,
lib/roby/distributed/protocol.rb,
lib/roby/transactions/updates.rb,
lib/roby/test/tasks/empty_task.rb,
lib/roby/test/tasks/simple_task.rb,
lib/roby/distributed/transaction.rb,
lib/roby/distributed/subscription.rb,
lib/roby/distributed/communication.rb,
lib/roby/distributed/notifications.rb,
lib/roby/distributed/connection_space.rb,
lib/roby/distributed/distributed_object.rb,
ext/droby/dump.cc,
lib/roby/relations/planned_by.rb,
lib/roby/relations/hierarchy.rb

Overview

The main namespace for the Roby library. The namespace is divided as follows:

Roby

core namespace for the Roby kernel

Roby::Distributed

parts that are very specific to distributed plan management

Roby::Planning

basic tools for plan generation

Roby::Transactions

implementation of transactions

Roby::EventStructure

event relations

Roby::TaskStructure

task relations

Defined Under Namespace

Modules: ConflictEventHandling, DirectedRelationSupport, Distributed, EventGeneratorDisplay, EventStructure, ExceptionHandlingObject, Executives, Log, LoggedPlan, LoggedPlanObject, LoggedTask, Planning, Pos, Propagation, Rake, TaskOperations, TaskStructure, Test, Transactions Classes: Aborting, AndGenerator, AndTaskMatcher, Application, BasicObject, ChildFailedError, CodeError, CommandFailed, ConfigError, Control, ControlQuitError, CycleFoundError, DecisionControl, DeltaEvent, EmissionFailed, Event, EventCanceled, EventGenerator, EventHandlerError, EventNotControlable, EventNotExecutable, EventPreconditionFailed, ExecutionException, ExtendedStruct, FailedExceptionHandler, FilterGenerator, Group, Interface, InternalError, InvalidReplace, InvalidTransaction, LocalizedError, MissionFailedError, ModelViolation, NegateTaskMatcher, OrGenerator, OrTaskMatcher, OwnershipError, Parallel, Plan, PlanObject, PlanningFailedError, PlanningLoop, PlanningTask, Pool, PosDeltaEvent, PropagationError, Query, RelationGraph, RelationSpace, RemoteInterface, RemoteObjectProxy, RemotePeerMismatch, Sequence, SolverIgnoreUpdate, SolverInvalidateTransaction, SolverUpdateRelations, StateEvent, StateSpace, Task, TaskAggregator, TaskEventGenerator, TaskIndex, TaskMatcher, TaskModelTag, TaskNotExecutable, ThreadMismatch, ThreadTask, TimeDeltaEvent, TimeDistribution, TimePointEvent, Transaction, UnreachableEvent, UntilGenerator, YawDeltaEvent

Constant Summary collapse

VERSION =
'0.7.2'
ROBY_LIB_DIR =
File.expand_path( File.join(File.dirname(__FILE__), '..') )
ROBY_ROOT_DIR =
File.expand_path( File.join(ROBY_LIB_DIR, '..') )
RX_IN_FRAMEWORK =
/^((?:\s*\(druby:\/\/.+\)\s*)?#{Regexp.quote(ROBY_LIB_DIR)}\/)/

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from ExceptionHandlingObject

handle_exception, pass_exception

Class Attribute Details

.condition_variablesObject (readonly)

A pool of condition variables (as a Queue)



76
77
78
# File 'lib/roby/control.rb', line 76

def condition_variables
  @condition_variables
end

.controlObject (readonly)

Returns the only one Control object



24
25
26
# File 'lib/roby/control.rb', line 24

def control
  @control
end

.decision_controlObject (readonly)

Returns the value of attribute decision_control.



12
13
14
# File 'lib/roby/decision_control.rb', line 12

def decision_control
  @decision_control
end

.exception_handlersObject (readonly)

Returns the value of attribute exception_handlers.



551
552
553
# File 'lib/roby/propagation.rb', line 551

def exception_handlers
  @exception_handlers
end

.mutexesObject (readonly)

A pool of mutexes (as a Queue)



74
75
76
# File 'lib/roby/control.rb', line 74

def mutexes
  @mutexes
end

.planObject (readonly)

Returns the executed plan. This is equivalent to

Roby.control.plan


27
28
29
# File 'lib/roby/control.rb', line 27

def plan
  @plan
end

Class Method Details

.appObject

Returns the only one Application object



12
# File 'lib/roby/app.rb', line 12

def self.app; Application.instance end

.check_failed_missions(plan) ⇒ Object

Get all missions that have failed



732
733
734
735
736
737
738
# File 'lib/roby/control.rb', line 732

def self.check_failed_missions(plan)
	result = []
	for task in plan.missions
 result << MissionFailedError.new(task) if task.failed?
	end
	result
end

.condition_variable(mutex = false) ⇒ Object

call-seq:

condition_variable => cv
condition_variable(true) => cv, mutex
condition_variable { |cv| ... } => value returned by the block
condition_variable(true) { |cv, mutex| ... } => value returned by the block

Get a condition variable object from the Roby.condition_variables pool and, if mutex is not true, a Mutex object

If a block is given, the two objects are yield and returned into the pool after the block has returned. In that case, the method returns the value returned by the block



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/roby/control.rb', line 90

def condition_variable(mutex = false)
    cv = condition_variables.pop

    if block_given?
	begin
	    if mutex
		mt = mutexes.pop
		yield(cv, mt)
	    else
		yield(cv)
	    end

	ensure
	    return_condition_variable(cv, mt)
	end
    else
	if mutex
	    return cv, mutexes.pop
	else
	    return cv
	end
    end
end

.control_threadObject

Returns the control thread or, if control is not in a separate thread, Thread.main



38
39
40
# File 'lib/roby/control.rb', line 38

def control_thread
    Control.instance.thread || Thread.main
end

.each_cycle(&block) ⇒ Object



32
33
34
# File 'lib/roby/control.rb', line 32

def each_cycle(&block)
    Control.each_cycle(&block)
end

.each_exception_handler(&iterator) ⇒ Object



552
# File 'lib/roby/propagation.rb', line 552

def each_exception_handler(&iterator); exception_handlers.each(&iterator) end

.every(duration, &block) ⇒ Object



29
30
31
# File 'lib/roby/control.rb', line 29

def every(duration, &block)
    Control.every(duration, &block)
end

.executeObject

Execute the given block inside the control thread, and returns when it has finished. The return value is the value returned by the block



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/roby/control.rb', line 116

def execute
    if Roby.inside_control?
	return Roby::Control.synchronize { yield }
    end

    cv = condition_variable

    return_value = nil
    Roby::Control.synchronize do
	if !Roby.control.running?
	    raise "control thread not running"
	end

	caller_thread = Thread.current
	Control.waiting_threads << caller_thread

	Roby::Control.once do
	    begin
		return_value = yield
		cv.broadcast
	    rescue Exception => e
		caller_thread.raise e, e.message, e.backtrace
	    end
                   Control.waiting_threads.delete(caller_thread)
	end
	cv.wait(Roby::Control.mutex)
    end
    return_value

ensure
    return_condition_variable(cv)
end

.filter_backtrace(original_backtrace) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/roby/exceptions.rb', line 147

def self.filter_backtrace(original_backtrace)
	if Roby.app.filter_backtraces? && original_backtrace
        app_dir = if defined? APP_DIR then Regexp.quote(APP_DIR) end

        original_backtrace = original_backtrace.dup
        backtrace_bottom   = []
        while !original_backtrace.empty? && original_backtrace.last !~ RX_IN_FRAMEWORK
            backtrace_bottom.unshift original_backtrace.pop
        end

        backtrace = original_backtrace.enum_for(:each_with_index).map do |line, idx|
            case line
            when /in `poll_handler'$/
                line.gsub /:in.*/, ':in the polling handler'
            when /in `event_command_(\w+)'$/
                line.gsub /:in.*/, ":in command for '#{$1}'"
            when /in `event_handler_(\w+)_(?:[a-f0-9]+)'$/
                line.gsub /:in.*/, ":in event handler for '#{$1}'"
            else
                if original_backtrace.size > idx + 4 &&
                    original_backtrace[idx + 1] =~ /in `call'$/ &&
                    original_backtrace[idx + 2] =~ /in `call_handlers'$/ &&
                    original_backtrace[idx + 3] =~ /`each'$/ &&
                    original_backtrace[idx + 4] =~ /`each_handler'$/

                    line.gsub /:in /, ":in event handler, "
                else
                    case line
                    when /in `(gem_original_)?require'$/
                    when /^((?:\s*\(druby:\/\/.+\)\s*)?#{Regexp.quote(ROBY_LIB_DIR)}\/)/
                    when /^(#{app_dir}\/)?scripts\//
                    when /^\(eval\):\d+:in `each(?:_handler)?'/
                    else
                        line
                    end
                end
            end
        end

        while !backtrace.empty? && !backtrace.last
            backtrace.pop
        end
        backtrace.each_with_index do |line, i|
            backtrace[i] = line || original_backtrace[i]
        end

        if app_dir
            backtrace = backtrace.map do |line|
                line.gsub /^#{app_dir}\/?/, './'
            end
        end
        backtrace.concat backtrace_bottom
	end
	backtrace || original_backtrace || []
end

.format_exception(exception) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/roby/exceptions.rb', line 211

def self.format_exception(exception)
    message = begin
                  PP.pp(exception, "")
              rescue Exception => formatting_error
                  begin
                      "error formatting exception\n" +
                          exception.full_message +
                      "\nplease report the formatting error: \n" + 
                          formatting_error.full_message
                  rescue Exception => formatting_error
                      "\nerror formatting exception\n" +
                          formatting_error.full_message
                  end
              end
    message.split("\n")
end

.inside_control?Boolean

True if the current thread is the control thread

See #outside_control? for a discussion of the use of #inside_control? and #outside_control? when testing the threading context

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/roby/control.rb', line 46

def inside_control?
    t = Control.instance.thread
    !t || t == Thread.current
end

.load_all_relationsObject

Requires all Roby relation files (all files in roby/relations/)



577
578
579
580
581
# File 'lib/roby/relations.rb', line 577

def self.load_all_relations
	Dir.glob("#{File.dirname(__FILE__)}/relations/*.rb").each do |file|
 require "roby/relations/#{File.basename(file, '.rb')}"
	end
end

.log_exception(e, logger, level) ⇒ Object



228
229
230
231
232
# File 'lib/roby/exceptions.rb', line 228

def self.log_exception(e, logger, level)
    format_exception(e).each do |line|
        logger.send(level, line)
    end
end

.on_exception(*matchers, &handler) ⇒ Object

define_method(:each_exception_handler, &Roby::Propagation.exception_handlers.method(:each))



554
555
556
557
# File 'lib/roby/propagation.rb', line 554

def on_exception(*matchers, &handler)
    check_arity(handler, 2)
    exception_handlers.unshift [matchers, handler]
end

.onceObject

Execute the given block in the control thread, but don’t wait for its completion like Roby.execute does



151
152
153
# File 'lib/roby/control.rb', line 151

def once
    Roby::Control.once { yield }
end

.outside_control?Boolean

True if the current thread is not control thread, or if there is not control thread. When you check the current thread context, always use a negated form. Do not do

if Roby.inside_control?
  ERROR
end

Do instead

if !Roby.outside_control?
  ERROR
end

Since the first form will fail if there is no control thread, while the second form will work. Use the first form only if you require that there actually IS a control thread.

Returns:

  • (Boolean)


68
69
70
71
# File 'lib/roby/control.rb', line 68

def outside_control?
    t = Control.instance.thread
    !t || t != Thread.current
end

.poll_state_eventsObject

Registered on Control to call the #poll method of state events



65
66
67
68
69
70
71
# File 'lib/roby/state/events.rb', line 65

def self.poll_state_events # :nodoc:
    for ev in Roby.plan.free_events
        if ev.kind_of?(StateEvent) && ev.enabled?
            ev.poll
        end
    end
end

.pretty_print_backtrace(pp, backtrace) ⇒ Object



203
204
205
206
207
208
209
# File 'lib/roby/exceptions.rb', line 203

def self.pretty_print_backtrace(pp, backtrace)
    if backtrace && !backtrace.empty?
        pp.group(2) do
            pp.seplist(filter_backtrace(backtrace)) { |line| pp.text line }
        end
    end
end

.RelationSpace(klass) ⇒ Object

Creates a new relation space which applies on klass. If a block is given, it is eval’d in the context of the new relation space instance



569
570
571
572
573
574
# File 'lib/roby/relations.rb', line 569

def self.RelationSpace(klass)
	klass.include DirectedRelationSupport
	relation_space = RelationSpace.new
    relation_space.apply_on klass
    relation_space
end

.return_condition_variable(cv, mutex = nil) ⇒ Object

Returns a ConditionVariable and optionally a Mutex into the Roby.condition_variables and Roby.mutexes pools



184
185
186
187
188
189
190
# File 'lib/roby/control.rb', line 184

def return_condition_variable(cv, mutex = nil)
    condition_variables.push cv
    if mutex
	mutexes.push mutex
    end
    nil
end

.wait_one_cycleObject



154
155
156
# File 'lib/roby/control.rb', line 154

def wait_one_cycle
    Roby.control.wait_one_cycle
end

.wait_until(ev) ⇒ Object

Stops the current thread until the given even is emitted



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/roby/control.rb', line 159

def wait_until(ev)
    if Roby.inside_control?
	raise ThreadMismatch, "cannot use #wait_until in control thread"
    end

    condition_variable(true) do |cv, mt|
	caller_thread = Thread.current

	mt.synchronize do
	    Roby::Control.once do
		ev.if_unreachable(true) do |reason|
		    caller_thread.raise UnreachableEvent.new(ev, reason)
		end
		ev.on do
		    mt.synchronize { cv.broadcast }
		end
		yield
	    end
	    cv.wait(mt)
	end
    end
end