Useful Tips

10/4/97


Where are the example programs?

The example programs can be found in the demos directory of the CAVERNsoft distribution. 

My 2 remote CAVERN programs don't seem to connect properly.

If on startup one CAVERN program does not seem to be able to connect to a remote CAVERN program running at a remote site, even though the 2 programs seem to work locally between 2 different computers: it maybe because your local and/or remote machine is not giving CAVERN its full hostname, but instead an abbreviated name. E.g. A full hostname might be ivan.evl.uic.edu. An abbreviated one would be ivan. You can tell if this is the case by typing: hostname at the unix prompt. To solve this problem you may need to add the following file to your home directory:

.resource_database

In it you need to place a declaration to identify the domain name of your local machine. (You may also need to do something similar on your remote machine). For example if your local machine is called ivan and the full hostname is actually ivan.evl.uic.edu you need to add the following line to the .resource_database file:

ivan domain=.evl.uic.edu


Can I run 2 CAVERNsoft programs on the same computer?

YES. Usually you do this if you wish to have one CAVERNsoft program connected to another CAVERNsoft program that happens to be running on the same computer (for the sake of convenience during debugging of your program.)

To do this each CAVERNsoft program must start on a different port. There are 2 ways to do this. The quick and dirty way is to simply set the CAVERN_PORT environment variable to the desired port. For example:

setenv CAVERN_PORT 9000

Alternatively you can do it from within the CAVERN program.
Here is an example of initializing 2 CAVERN programs to run on 2 different ports.

Program1:

CAVERN_initAttrib_c initAttr;
initAttr.setPort(7771);
personalIRB = CAVERNInit(&argc,&argv, &initAttr);
Program2:
CAVERN_initAttrib_c initAttr;
initAttr.setPort(7772);
personalIRB = CAVERNInit(&argc, &argv, &initAttr);
Program 1 will initialize CAVERN on port 7771 and program 2 on port 7772.

Now, for example, in order for program 1 to open a connection to program 2, program 1 must do the following:

CAVERN_irbChannel_c *aChannel = personalIRB->createChannel();
CAVERN_irbId_c remoteIRB;
// Insert your own hostname below.
remoteIRB.setAddress("ivan.evl.uic.edu");
// Program 2's port is specified here.
remoteIRB.setPort(7772);
aChannel->open(&remoteIRB, NULL, CAVERN_irbChannel::RELIABLE, &status);


How to take a UNIX file and insert it into a local CAVERNsoft data store

By default CAVERNsoft will create a data store directory in the same directory in which the CAVERNsoft-based program runs. This directory is usually called CAVERN_DEFAULT_DB. To make a UNIX file a part of this database simply move the file into the CAVERN_DEFAULT_DB directory and run a program called: on the file. This program is located in the tools directory of the CAVERNsoft distribution directory.


How to take a UNIX file and upload it into a remote CAVERNsoft IRB.

If you wish to upload a UNIX file into a remote IRB (the remote IRB must already be running for this to work) use the program called: The syntax is: where: This program is located in the tools directory of the CAVERNsoft distribution.

How to download data in a remote IRB to a local UNIX file.

If you wish to download the data stored in a key on a remote IRB to a local UNIX file use the program called: The syntax is: where: This program is located in the tools directory of the CAVERNsoft distribution.

Debugging a CAVERNsoft program

It is difficult to debug CAVERNsoft programs with DBX since DBX on the SGI's is not designed to work well with threaded programs. Unfortunately printfs are your main salvation. CAVERNsoft provides a thread-safe printf that you can use to print your own debug messages. Its prototype is:

How to use channels efficiently

As CAVERNsoft allows you to link any number of keys over any given channel there may be some ambiguity over what is the optimum number of channels to create and what is the optimum number of links to assign to each channel. Also there is the issue of what kinds of channels are best for transporting different kinds of data. Here are a few rules of thumb:

For transporting avatar tracker information a separate unreliable channel should be assigned. This channel can host all the tracker traffic for the avatars.

For information that conveys the state of entities in the virtual environment use a separate reliable channel.

For sharing 3D geometries between clients etc, use yet another separate channel. Do not simply combine the latter 2 channels together as large amounts of geometry data can easily slow down smaller state data. By assigning them to separate channels the transmission of the data is interlaced. 


CAVERNsoft Fault Tolerance Provisions

CAVERNsoft was designed with persistence in mind and hence it makes every effort to not crash or terminate a program when channels and links are closed or broken. Instead it offers callbacks to user-specified functions that can be used to alert the program of such events. The program can then proceed to attempt to re-establish the channel. At the current time this must be done manually by the user. In the future, CAVERNsoft will attempt to re-establish connections automatically.

So currently when you receive an event that a channel has broken, simply delete and create a new channel object, delete all the previous link objects and then create all new links with the newly open channel. You do not have to redefine the keys. Those will not be affected. Note however that we can't protect you against your own accidental accesses to dangling memory pointers. Those will surely kill your program however they should not adversely affect the remote IRB programs to which your program may be connected. Your disappearance will eventually be noticed and any resources that you may have held subsequently recycled.

As part of CAVERNsoft's fault tolerance provisions, you may notice that there are some status values returned from the various C++ member functions that state that a link, channel, or key is no longer valid (or stale). These statuses are provided so that you do not accidentally access dangling pointers that point to deleted objects. Everytime you access any of CAVERNsoft's object member functions it verifies that you are accessing a valid object before it proceeds. This allows CAVERNsoft to dynamically tear down broken connections and reclaim system resources without adversely affecting your program.

To reclaim resources CAVERNsoft spawns off a separate garbage collection thread which monitors your personal IRB every 10 seconds. Hence some times when you disconnect from an IRB-based server and then reconnect too soon, it may not allow you to re-create certain links because the old links have not yet been purged from the system. After 10 seconds you can try again and odds are, everything will be fine. Later we will provide a more responsive garbage collection system. 


CAVERNsoft and concurrency

CAVERNsoft is written with Nexus' threads package which are basically macro definitions over pthreads. Hence if you need to, you may create your own threads by using the standard pthreads or Nexus threads calls. If you have never programmed with threads before it may be easier to use CAVERN's thread classes (CAVERNplus_thread_c, CAVERNplus_mutex_c, CAVERNplus_condition_c). These are classes that encapsulate the most basic functionality of Nexus/pthreads.

CAUTIONARY NOTE: You should exercise caution when working with fork() as forking copies of threads can produce unpredicatable results. In general the best policy is to perform all your forks before calling CAVERNInit(). Hence in the CAVE, CAVERNInit should be done after the CAVE has forked off all its draw processes.

 


Miscellaneous References