Next

Prev

Prev-tail

Tail

Up

Chapter 15
Frequently Asked Questions

 15.1 Build Issues
  15.1.1 Complaints about ‘+=
  15.1.2 error: ‘¡anonymous¿’ is used uninitialized in this function
  15.1.3 AM_LANGINFO_CODESET
  15.1.4 make check’ fails
 15.2 Troubleshooting
  15.2.1 Error 1723: ”A DLL required for this install to complete could not be run.”
  15.2.2 When executing a program, the message “The system cannot execute the specified program.” is raised.
  15.2.3 When executing a program, the message “This application has failed to start” is raised.
  15.2.4 The server dies with “stack exhaustion”
  15.2.5 ’myuobject: file not found’. What can I do?
15.2.5.1 Getting a better diagnostic
15.2.5.2 GNU/Linux
15.2.5.3 Mac OS X
15.2.5.4 Windows

 15.3 urbiscript
  15.3.1 Objects lifetime
15.3.1.1 How do I create a new Object derivative?
15.3.1.2 How do I destroy an Object?

  15.3.2 Slots and variables
15.3.2.1 Is the lobby a scope?
15.3.2.2 How do I add a new slot in an object?
15.3.2.3 How do I modify a slot of my object?
15.3.2.4 How do I create or modify a local variable?
15.3.2.5 How do I make a constructor?
15.3.2.6 How can I manipulate the list of prototypes of my objects?
15.3.2.7 How can I know the slots available for a given object?
15.3.2.8 How do I create a new function?

  15.3.3 Tags
15.3.3.1 How do I create a tag?
15.3.3.2 How do I stop a tag?
15.3.3.3 Can tagged statements return a value?

  15.3.4 Events
15.3.4.1 How do I create an event?
15.3.4.2 How do I emit an event?
15.3.4.3 How do I catch an event?

  15.3.5 Standard Library
15.3.5.1 How can I iterate over a list?

 15.4 UObjects
  15.4.1 Is the UObject API Thread-Safe?
15.4.1.1 Plugin mode
15.4.1.2 Remote mode

 15.5 Miscellaneous
  15.5.1 What has changed since the latest release?
  15.5.2 How can I contribute to the code?
  15.5.3 How do I report a bug?

15.1 Build Issues

15.1.1 Complaints about ‘+=

At random places we use ‘+=’ in /bin/sh scripts, which Ash (aka, dash and sash) does not support. Please, use bash or zsh instead of Ash as /bin/sh.

15.1.2 error: ‘¡anonymous¿’ is used uninitialized in this function

If you encounter this error:

cc1plus: warnings being treated as errors 
parser/ugrammar.hh: In member function \ 
  void yy::parser::yypush_(const char*, int, yy::parser::symbol_type&)’: 
parser/ugrammar.hh:1240: error: ‘<anonymous>’ is used uninitialized \ 
  in this function 
parser/ugrammar.cc:1305: note: ‘<anonymous>’ was declared here 
parser/ugrammar.hh: In member function \ 
  void yy::parser::yypush_(const char*, yy::parser::stack_symbol_type&)’: 
parser/ugrammar.hh:1240: error: ‘<anonymous>’ is used uninitialized \ 
  in this function 
parser/ugrammar.cc:1475: note: ‘<anonymous>’ was declared here

then you found a problem that we don’t know how to resolved currently. Downgrade from GCC-4.4 to GCC-4.3.

15.1.3 AM_LANGINFO_CODESET

If at bootstrap you have something like:

configure:12176: error: possibly undefined macro: AM_LANGINFO_CODESET 
 If this token and others are legitimate, please use m4_pattern_allow. 
 See the Autoconf documentation. 
configure:12246: error: possibly undefined macro: gl_GLIBC21

it probably means your Automake installation is incomplete. See the Automake item in Section 17.1.

15.1.4 make check’ fails

Be sure to read Section 17.9. In particular, run ‘make check’ several times (see Section 17.9 to know why). If the failures remain, please submit the ‘test-suite.log’ file(s) (see Section 15.5.3).

15.2 Troubleshooting

15.2.1 Error 1723: ”A DLL required for this install to complete could not be run.”

This error is raised when you try to install a program like vcredist-x86.exe. This program use the “Windows Installer” which is probably outdated on your system.

To fix this problem, update the “Windows Installer” and re-start the installation of vcredist which should no longer fail.

15.2.2 When executing a program, the message “The system cannot execute the specified program.” is raised.

This library is necessary to start running any application. Run ‘vcredist-x86.exe’ to install the missing libraries.

If you have used the Urbi SDK installer, it is ‘vcredist-x86.exe’ in your install directory. Otherwise download it from the Microsoft web site. Be sure to get the one corresponding to the right Visual C ++ version.

15.2.3 When executing a program, the message “This application has failed to start” is raised.

Same answer as Section 15.2.2.

15.2.4 The server dies with “stack exhaustion”

Your program might be deeply recursive, or use large temporary objects. Use ‘--stack-size’ to augment the stack size, see Section 18.3.

Note that one stack is allocated per “light thread”. This can explain why programs that heavily rely on concurrency might succeed where sequential programs can fail. For instance the following program is very likely to quickly exhaust the (single) stack.

 
function consume (var num) 
{ 
  if (num) 
    consume(num - 1) | consume(num - 1) 
}|; 
consume (512);  

But if you use & instead of |, then each recursive call to consume will be spawn with a fresh stack, and therefore none will run out of stack space:

 
function consume (var num) 
{ 
  if (num) 
    consume(num - 1) & consume(num - 1) 
}|; 
consume (512);  

However your machine will run out of resources: this heavily concurrent program aims at creating no less than 2513 threads, about 2.68 × 10156 (a 156-digit long number, by far larger than the number of atoms in the observable universe, estimated to 1080).

15.2.5 ’myuobject: file not found’. What can I do?

If urbi-launch (or urbi) fails to load an UObject (a shared library or DLL) although the file exists, then the most probable cause is an undefined symbol in your shared library.

15.2.5.1Getting a better diagnostic
First, set the GD_LEVEL environment variable (see Section 18.1.2) to some high level, say DUMP, to log messages from urbi-launch. You might notice that your library is not exactly where you thought urbi-launch was looking at.

15.2.5.2GNU/Linux
A libltdl quirk prevents us from displaying a more accurate error message. You can use a tool named ltrace to obtain the exact error message. Ltrace is a standard package on most Linux distributions. Run it with ‘ltrace -C -s 1024 urbi-launch ...’, and look for lines containing ‘dlerror’ in the output. One will contain the exact message that occurred while trying to load your shared library.

It is also useful to use ldd to check that the dependencies of your object are correct. See the documentation of ldd on your machine (‘man ldd’). The following run is successful: every request (left-hand side of =>) is satisfied (by the file shown on the right-hand side).

 
$ all.so 
        linux-gate.so.1 =>  (0xb7fe8000) 
        libstdc++.so.6 => \ 
          /usr/lib/gcc/i686-pc-linux-gnu/4.4.1/libstdc++.so.6 (0xb7eba000) 
        libm.so.6 => /lib/libm.so.6 (0xb7e94000) 
        libc.so.6 => /lib/libc.so.6 (0xb7d51000) 
        libgcc_s.so.1 => \ 
          /usr/lib/gcc/i686-pc-linux-gnu/4.4.1/libgcc_s.so.1 (0xb7d35000) 
        /lib/ld-linux.so.2 (0xb7fe9000)  

The following run shows a broken dependency.

 
# A simple C++ program. 
$ echo int main() {} >foo.cc 
 
# Compile it, and depend on the libport shared library. 
$ g++ foo.cc -Lurbi-root/gostai/lib -lport -o foo 
 
# Run it. 
$ ./foo 
./foo: error while loading shared libraries: \ 
  libport.so: cannot open shared object file: No such file or directory 
 
# See that ldd is unhappy. 
$ ldd foo 
        linux-gate.so.1 =>  (0xb7fa4000) 
        libport.so => not found 
        libstdc++.so.6 => \ 
          /usr/lib/gcc/i686-pc-linux-gnu/4.4.1/libstdc++.so.6 (0xb7eae000) 
        libm.so.6 => /lib/libm.so.6 (0xb7e88000) 
        libgcc_s.so.1 => \ 
          /usr/lib/gcc/i686-pc-linux-gnu/4.4.1/libgcc_s.so.1 (0xb7e6c000) 
        libc.so.6 => /lib/libc.so.6 (0xb7d29000) 
        /lib/ld-linux.so.2 (0xb7fa5000)  

Notice the ‘not found’ message. The shared object could not be loaded because it is not found in the runtime path, which is the list of directories where the system looks for shared objects to be loaded when running a program.

You may extend your LD_LIBRARY_PATH to include the missing directory.

 
$ export LD_LIBRARY_PATH=urbi-root/gostai/lib:$LD_LIBRARY_PATH 
# Run it. 
$ ./foo  

15.2.5.3Mac OS X
Set the DYLD_PRINT_LIBRARIES environment variable to 1 to make the shared library loader report the libraries it loads on the standard error stream.

Use otool to check whether a shared object “finds” all its dependencies.

 
$ otool -L all.so 
all.so: 
        /usr/lib/libstdc++.6.dylib \ 
          (compatibility version 7.0.0, current version 7.4.0) 
        /usr/lib/libgcc_s.1.dylib \ 
          (compatibility version 1.0.0, current version 1.0.0) 
        /usr/lib/libSystem.B.dylib \ 
          (compatibility version 1.0.0, current version 111.1.4)  

The following run shows a broken dependency.

 
# A simple C++ program. 
$ echo int main() {} >foo.cc 
 
# Compile it, and depend on the libport shared library. 
$ g++ foo.cc -Lurbi-root/gostai/lib -lport -o foo 
 
# Run it. 
$ ./foo 
dyld: Library not loaded: @loader_path/libport.dylib 
  Referenced from: /private/tmp/./foo 
  Reason: image not found 
 
# See that otool is unhappy. 
$ otool -L ./foo 
./foo: 
        @loader_path/libport.dylib \ 
          (compatibility version 0.0.0, current version 0.0.0) 
        /usr/lib/libstdc++.6.dylib \ 
          (compatibility version 7.0.0, current version 7.4.0) 
        /usr/lib/libgcc_s.1.dylib \ 
          (compatibility version 1.0.0, current version 1.0.0) 
        /usr/lib/libSystem.B.dylib \ 
          (compatibility version 1.0.0, current version 111.1.5)  

The fact that the ‘libport.dylib’ was not found shows by the unresolved relative runtime-path: ‘@loader_path’ still shows. Use DYLD_LIBRARY_PATH to specify additional directories where the system should look for runtime dependencies.

 
$ DYLD_PRINT_LIBRARIES=1 \ 
  DYLD_LIBRARY_PATH=urbi-root/lib:$DYLD_LIBRARY_PATH \ 
  ./foo 
dyld: loaded: /private/tmp/./foo 
dyld: loaded: urbi-root/lib/libport.dylib 
dyld: loaded: /usr/lib/libstdc++.6.dylib 
dyld: loaded: /usr/lib/libgcc_s.1.dylib 
dyld: loaded: /usr/lib/libSystem.B.dylib 
dyld: loaded: urbi-root/lib/libboost_filesystem-mt.dylib 
dyld: loaded: urbi-root/lib/libboost_signals-mt.dylib 
dyld: loaded: urbi-root/lib/libboost_system-mt.dylib 
dyld: loaded: urbi-root/lib/libboost_thread-mt.dylib 
dyld: loaded: /usr/lib/system/libmathCommon.A.dylib 
$  

15.2.5.4Windows

If you are running Cygwin, then have a look at the following section, which uses some of its tools.

A specific constraint, for which currently we do not have nice solutions, is that when Windows loads a DLL, it looks for all its dependencies (i.e., other DLL that are needed) in the directory from which the program was run, or in the PATH. There is no way, that we are aware of, to embed in a DLL the information about where the dependencies are. When trying to load a DLL with missing dependencies, say ‘foo.dll’, the error message will be something like “can’t open the module”, and worse yet, if you read the detailed log messages (by setting GD_LEVEL to DUMP for instance) it will report “failed with error 126: The specified module could not be found” although the file is there.

So first try to understand what are the missing dependencies. Under Windows, use DependencyWalker (see http://dependencywalker.com) to check that a given DLL finds all its dependencies. If some dependencies are not found either:

The first approach is more tractable. Beware that dependencies may also have dependencies…

Cygwin Use the cygcheck.exe program to check dependencies. Beware that you must provide a qualified path to the file. Chances are that if

 
$ cygcheck foo.dll  

does not work and will pretend that ‘foo.dll’ does not exist (although it’s right there), then this will work:

 
$ cygcheck ./foo.dll  

In this output, look for lines like these:

 
cygcheck: track_down: could not find OgreMain.dll 
cygcheck: track_down: could not find OIS.dll 
cygcheck: track_down: could not find libuobject-vc90.dll  

and make sure that ‘OgreMain.dll’, ‘OIS.dll’ and so forth are visible in the PATH (don’t be worry about ‘libuobject-vc90.dll’, urbi-launch will take care of it). Note that when they are finally visible from the PATH, then you can run

 
$ cygcheck OgreMain.dll  

without having to specify the path.

15.3 urbiscript

15.3.1 Objects lifetime

15.3.1.1How do I create a new Object derivative?
Urbi is based on prototypes. To create a new Object derivative (which will inherit all the Object methods), you can do:

 
var myObject = Object.new; 
[00000001] Object_0x76543210  

15.3.1.2How do I destroy an Object?
There is no delete in Urbi, for a number of reasons (see Section 16.2). Objects are deleted when they are no longer used/referenced to.

In practice, users who want to “delete an object” actually want to remove a slot — see Section 6.1. Users who want to clear an object can empty it — see Section 16.2.

Note that myObject = nil does not explicitly destroy the object bound to the name myObject, yet it may do so provided that myObject was the last and only reference to this object.

15.3.2 Slots and variables

15.3.2.1Is the lobby a scope?

One frequently asked question is what visibility do variables have in urbiscript, especially when they are declared at the top-level interactive loop. In this section, we will see the mechanisms behind slots, local variables and scoping to fully explain this behavior and determine how to proceed to give the right visibility to variables.

For instance, this code might seem confusing at first:

 
var mind = 42; 
[00000001] 42 
function get() 
{ 
  echo(mind); 
}|; 
get(); 
[00000000] *** 42 
function Object.get() 
{ 
  echo(mind) 
}|; 
// Where is my mind? 
Object.get; 
[00000006:error] !!! lookup failed: mind 
[00000007:error] !!!    called from: echo 
[00000008:error] !!!    called from: get  

Local variables, slots and targets The first point is to understand the difference between local variables and slots. Slots are simply object fields: a name in an object referring to another object, like members in C ++. They can be defined with the setSlot method, or with the var keyword.

 
// Add an x slot in Object, with value 51. 
Object.setSlot("x", 51); 
[00000000] 51 
// This is an equivalent version, for the y slot. 
var Object.y = 51; 
[00000000] 51 
 
// We can access these slots with the dot operator. 
Object.x + Object.y; 
[00000000] 102  

On the other hand, local variables are not stored in an object, but in the execution stack: their lifetime spans from their declaration point to the end of the current scope. They are declared with the ‘var’ keyword.

 
function foo() 
{ 
  // Declare an x local variable, with value 51. 
  var x = 51; 
  // x isnt stored in any object. Its simply 
  // available until the end of the scope. 
  echo(x); 
}|;  

You probably noticed that in the last two code snippets, we used the var keyword to declare both a slot in Object and a local variable. The rule is simple: var declares a slot if an owning object is specified with the dot notation, as in var owner.slot, and a local variable if only an unqualified name is given, as in var name.

 
{ 
  // Store a kyle slot in Object. 
  var Object.kyle = 42; 
  // Declare a local variable, limited to this scope. 
  var kenny = 42; 
}; // End of scope. 
[00000000] 42 
 
// Kyle survived. 
echo(Object.kyle); 
[00000000] *** 42 
 
// Oh my God, they killed Kenny. 
echo(kenny); 
[00000000:error] !!! lookup failed: kenny  

There is however an exception to this rule: do and class scopes are designed to define a target where to store slots. Thus, in do and class scopes, even unqualified var uses declare slots in the target.

 
// Classical scope. 
{ 
  var arm = 64; // Local to the scope. 
}; 
[00000000] 64 
 
// Do scope, with target Object 
do (Object) 
{ 
  var chocolate = 64; // Stored as a slot in Object. 
}; 
[00000000] Object 
 
// No arm... 
echo(arm); 
[00000000:error] !!! lookup failed: arm 
// ... but still chocolate! 
echo(chocolate); 
[00000000] *** 64  

Last tricky rule you must keep in mind: the top level of your connection — your interactive session — is a do (lobby) scope. That is, when you type var x directly in your connection, it stores an x slot in the lobby object. So, what is this lobby? It’s precisely the object designed to store your top-level variables. Every Urbi server has an unique Lobby (Section 20.32) (note the capital), and every connection has its lobby that inherits the Lobby. Thus, variables stored in Lobby are accessible from any connection, while variables stored in a connection’s lobby are local to this connection.

To fully understand how lobbies and the top-level work, we must understand how calls — message passing — work in urbiscript. In urbiscript, every call has a target. For instance, in Object.x, Object is the target of the x call. If no target is specified, as in x alone, the target defaults to this, yielding this.x. Knowing this rules, plus the fact that at the top-level this is lobby, we can understand better what happens when defining and accessing variables at the top-level:

 
// Since we are at the top-level, this stores x in the lobby. 
// It is equivalent to var lobby.x’. 
var x = "hello"; 
[00000000] "hello" 
 
// This is an unqualified call, and is thus 
// equivalent to this.x’. 
// That is, lobby.x would be equivalent. 
x; 
[00000000] "hello"  

Solving the tricky example We now know all the scoping rules required to explain the behavior of the first code snippet. First, let’s determine why the first access to mind works:

 
// This is equivalent to var lobby.myMind = 42’. 
var myMind = 42; 
[00000001] 42 
// This is equivalent to function lobby.getMine...’ 
function getMine() 
{ 
  // This is equivalent to echo(this.myMind)’ 
  echo(myMind); 
}|; 
// This is equivalent to this.getMine()’, i.e. lobby.getMine()’. 
getMine(); 
[00000000] *** 42  

Step by step:

We can also explain why the second test fails:

 
// Create the hisMind slot in the lobby. 
var hisMind = 42; 
[00000000] 42 
// Define a getHis method in Object’. 
function Object.getHis() 
{ 
  // Equivalent to echo(this.hisMind). 
  echo(hisMind) 
}|; 
// Call Objects getHis method. 
Object.getHis; 
[00000032:error] !!! lookup failed: hisMind 
[00000032:error] !!!    called from: echo 
[00000033:error] !!!    called from: getHis  

Step by step:

In the method, this is Object. Thus hisMind, which is this.hisMind, fails because Object has no such slot.

The key to understanding this behavior is that any unqualified call — unless it refers to a local variable — is destined to this. Thus, variables stored in the lobby are only accessible from the top-level, or from functions that are targeted on the lobby.

So, where to store global variables? From these rules, we can deduce a simple statement: since unqualified slots are searched in this, for a slot to be global, it must always be accessible through this. One way to achieve this is to store the slot in Object, the ancestor of any object:

 
var Object.global = 1664; 
[00000000] 1664 
 
function any_object() 
{ 
  // This is equivalent to echo(this.global) 
  echo(global); 
}|;  

In the previous example, typing global will look for the global slot in this. Since this necessarily inherits Object, it will necessarily be found.

This solution would work; however, storing all global variables in Object wouldn’t be very clean. Object is rather designed to hold methods shared by all objects. Instead, a Global object exists. This object is a prototype of Object, so all his slots are accessible from Object, and thus from anywhere. So, creating a genuine global variable is as simple as storing it in Global:

 
var Global.g = "Im global!"; 
[00000000] "Im global!"  

Note that you might want to reproduce the Global system and create your own object to store your related variables in a more tidy fashion. This is for instance what is done for mathematical constants:

 
// Store all constants here 
class Constants 
{ 
  var Pi = 3.14; 
  var Euler = 2.17; 
  var One = 1; 
  // ... 
}|; 
// Make them global by making them accessible from Global. 
Global.addProto(Constants); 
[00000000] Global 
 
// Test it. 
Global.Pi; 
[00000000] 3.14 
Pi; 
[00000000] 3.14 
function Object.testPi() { echo(Pi) }|; 
42.testPi; 
[00000000] *** 3.14  

15.3.2.2How do I add a new slot in an object?
To add a slot to an object O, you have to use the var keyword, which is syntactic sugar for the setSlot method:

 
var O2 = Object.new | 
// Syntax... 
var O2.mySlot1 = 42; 
[00000001] 42 
 
// and semantics. 
O2.setSlot("mySlot2", 23); 
[00000001] 23  

Note that in a method, this designates the current object. It is needed to distinguish the name of a slot in the current object, versus a local variable name:

 
{ 
  // Create a new slot in the current object. 
  var this.bar = 42; 
 
  // Create a local variable, which will not be known anymore 
  // after we exit the current scope. 
  var qux = 23; 
}| 
qux; 
[00000001:error] !!! lookup failed: qux 
bar; 
[00000001] 42  

15.3.2.3How do I modify a slot of my object?
Use the = operator, which is syntactic sugar for the updateSlot method.

 
class O 
{ 
  var mySlot = 42; 
}| 
// Sugarful. 
O.mySlot = 51; 
[00000001] 51 
 
// Sugar-free. 
O.updateSlot("mySlot", 23); 
[00000001] 23  

15.3.2.4How do I create or modify a local variable?
Use var and =.

 
// In two steps: definition, and initial assignment. 
var myLocalVariable; 
myLocalVariable = "foo"; 
[00000001] "foo" 
// In a single step: definition with an initial value. 
var myOtherLocalVariable = "bar"; 
[00000001] "bar"  

15.3.2.5How do I make a constructor?
You can define a method called init which will be called automatically by new. For example:

 
class myObject 
{ 
  function init(x, y) 
  { 
    var this.x = x; 
    var this.y = y; 
  }; 
}; 
myInstance = myObject.new(10, 20);  

15.3.2.6How can I manipulate the list of prototypes of my objects?
The protos method returns a list (which can be manipulated) containing the list of your object prototype.

 
var myObject = Object.new; 
myObject.protos; 
[00000001] [Object]  

15.3.2.7How can I know the slots available for a given object?
The localSlotNames and allSlotNames methods return respectively the local slot names and the local+inherited slot names.

15.3.2.8How do I create a new function?
Functions are first class objects. That means that you can add them as any other slot in an object:

 
var myObject = Object.new; 
var myObject.myFunction = function (x, y) 
  { echo ("myFunction called with " + x + " and " + y) };  

You can also use the following notation to add a function to your object:

 
var myObject = Object.new; 
function myObject.myFunction (x, y) { /* ... */ };  

or even group definitions within a do scope, which will automatically define new slots instead of local variables and functions:

 
var myObject = Object.new; 
do (myObject) 
{ 
  function myFunction (x, y) { /* ... */ }; 
};  

or group those two statements by using a convenient class scope:

 
class myObject 
{ 
  function myFunction (x, y) { /* ... */ }; 
};  

15.3.3 Tags

See Section 11.3, in the urbiscript User Manual, for an introduction about Tags. Then for a definition of the Tag objects (construction, use, slots, etc.), see Tag (Section 20.61).

15.3.3.1How do I create a tag?
See Section 20.61.2.

15.3.3.2How do I stop a tag?
Use the stop method (see Section 20.61.1.1).

 
myTag.stop;  

15.3.3.3Can tagged statements return a value?
Yes, by giving it as a parameter to stop. See Section 20.61.1.1.

15.3.4 Events

See Listing 12, in the urbiscript User Manual, for an introduction about event-based programming. Then for a definition of the Event objects (construction, use, slots, etc.), see Event (Section 20.14).

15.3.4.1How do I create an event?
Events are objects, and must be created as any object by using new to create derivatives of the Event object.

 
var ev = Event.new;  

See Section 20.14.3.

15.3.4.2How do I emit an event?
Use the ! operator.

 
ev!(1, "foo");  

15.3.4.3How do I catch an event?
Use the at(event?args) construct (see Listing 19.9.1).

 
at(ev?(1, var msg)) 
  echo ("Received event with 1 and message " + msg);  

The ? marker indicates that we are looking for an event instead of a Boolean condition. The construct var msg indicates that the msg variable will be bound (as a local variable) in the body part of the at construct, with whatever value is present in the event that triggered the at.

15.3.5 Standard Library

15.3.5.1How can I iterate over a list?
Use the for construct (Section 19.6.5.2), or the each method (List (Section 20.30)):

 
for (var i: [10, 11, 12]) echo (i); 
[00000001] *** 10 
[00000002] *** 11 
[00000003] *** 12  

15.4 UObjects

15.4.1 Is the UObject API Thread-Safe?

We are receiving a lot of questions on thread-safety issues in UObject code. So here comes a quick explanation on how things work in plugin and remote mode, with a focus on those questions.

15.4.1.1Plugin mode

In plugin mode, all the UObject callbacks (timer, bound functions, notifyChange and notifyAccess targets) are called synchronously in the same thread that executes urbiscript code. All reads and writes to Urbi variables, through UVar, are done synchronously. Access to the UObject API (reading/writing UVars, using call()...) is possible from other threads, though those operations are currently using one serialization lock with the main thread: each UObject API call from an other thread will wait until the main thread is ready to process it.

15.4.1.2Remote mode

Execution model In remote mode, a single thread is also used to handle all UObject callbacks, for all the UObjects in the same executable. It means that two bound functions registered from the same executable will never execute in parallel. Consider this sample C ++ function:

 
int MyObject::test(int delay) 
{ 
  static const int callNumber = 0; 
  int call = ++callNumber; 
  std::cerr << "in "  << call << ": " << time() << std::endl; 
  sleep(delay); 
  std::cerr << "out " << call << ": " << time() << std::endl; 
  return 0; 
}  

If this function is bound in a remote uobject, the following code:

 
MyObject.test(1), MyObject.test(1)  

will produce the following output (assuming the first call to time returns 1000).

in 1: 1000 
out 1: 1001 
in 2: 1001 
out 2: 1002

However, the execution of the Urbi kernel is not “stuck” while the remote function executes, as the following code demonstrates:

 
var t = Tag.new; 
test(1) | t.stop, 
t:every(300ms) 
  cerr << "running";  

The corresponding output is (mixing the kernel and the remote outputs):

[0] running 
in 1: 1000 
[300] running 
[600] running 
[900] running 
out 1: 1001

As you can see, Urbi semantics is respected (the execution flow is stuck until the return value from the function is returned), but the kernel is not stuck: other pieces of code are still running.

Thread-safety The liburbi and the UObject API in remote mode are thread safe. All operations can be performed in any thread. As always, care must be taken for all non-atomic operations. For example, the following function is not thread safe:

 
void 
writeToVar(UClient* cl, std::string varName, std::string value) 
{ 
  (*cl) << varName << " = " << value << ";"; 
}  

Two simultaneous calls to this function from different threads can result in the two messages being mixed. The following implementation of the same function is thread-safe however:

 
void 
writeToVar(UClient* cl, std::string varName, std::string value) 
{ 
  std::stringstream s; 
  s << varName << " = " << value << ";"; 
  (*cl) << s.str(); 
}  

since a single call to UClient’s operator << is thread-safe.

15.5 Miscellaneous

15.5.1 What has changed since the latest release?

See Listing 31.

15.5.2 How can I contribute to the code?

You are encouraged to submit patches to kernel@lists.gostai.com, where they will be reviewed by the Urbi team. If they fit the project and satisfy the quality requirements, they will be accepted. As of today there is no public repository for Urbi SDK (there will be, eventually), patches should be made against the latest source tarballs (see http://gostai.com/downloads/urbi-sdk/2.x/).

Even though Urbi SDK is free software (GNU Affero General Public License 3+, see the ‘LICENSE.txt’ file), licensing patches under GNU AGPL3+ does not suffice to support our dual licensed products. This situation is common, see for instance the case of Oracle VM Virtual Box, http://www.virtualbox.org/wiki/Contributor_information.

There are different means to ensure that your contributions to Urbi SDK can be accepted. None require that you “give away your copyright”. What is needed, is the right to use contributions, which can be achieved in two ways:

15.5.3 How do I report a bug?

Bug reports should be sent to kernel-bugs@lists.gostai.com, it will be addressed as fast as possible. Please, be sure to read the FAQ (possibly updated on our web site), and to have checked that no more recent release fixed your issue.

Each bug report should contain a self-contained example, which can be tested by our team. Using self-contained code, i.e., code that does not depend on other code, helps ensuring that we will be able to duplicate the problem and analyze it promptly. It will also help us integrating the code snippet into our non-regression test suite so that the bug does not reappear in the future.

If your report identifies a bug in the Urbi kernel or its dependencies, we will prepare a fix to be integrated in a later release. If the bug takes some time to fix, we may provide you with a workaround so that your developments are not delayed.

In your bug report, make sure that you indicate the Urbi version you are using (use ‘urbi --version’ to check it out) and whether this bug is blocking you or not. Also, please keep kernel-bugs@lists.gostai.com in copy of all your correspondence, and do not reply individually to a member of our team as this may slow down the handling of the report.

If your bug report is about a failing ‘make check’, first be sure to read Section 17.9.