There are now new Makefile includes:
CAVERN_MAKEFILE_INCLUDE_PTHREAD_32, CAVERN_MAKEFILE_INCLUDE_PTHREAD_N32, CAVERN_MAkEFILE_INCLUDE_SPROC_32, and CAVERN_MAKEFILE_INCLUDE_SPROC_N32.
Use these instead of the standard CAVERN_MAKEFILE_INCLUDES_32 and CAVERN_MAKEFILE_INCLUDES_N32.
In the SPROC library you have a limit on the maximum number of threads and mutexes/condition variables that can be created. This limit is set a default of 64 threads and 4194304 bytes (4Mb). If your program appears to crash at the creation of a new thread or mutex and you happen to be creating lots of keys, links, channels etc, you may need to increase those default values.
There are 2 ways to do this. Either by setting the following environment
setting the values in CAVERN_initAttrib_c that is used by CAVERNInit().
Another thing you must remember to do when using the SPROC version is that when you exit your CAVERN program you need to do the proper cleanup. This basically amounts to deleting your CAVERN_irb_c object which will perform a proper shutdown of Globus hence closing all SPROCs. If you simply hit Ctrl C the SPROCs will remain and will prevent you from running another CAVERNsoft program that uses the same network ports.
Eventually Globus will trap for interrupts and do the appropriate cleanup.
CAVERN: CAVERNInit: Listening on Hailing Channel: x-nexus://ivan:10000/
To solve this problem you will need to add the following file to your home directory:
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:
The next time your run the CAVERN program you should instead see something like this:
CAVERN: CAVERNInit: Listening on Hailing Channel: x-nexus://ivan.evl.uic.edu:10000/
If for some strange reason this still does not appear to work then try the following and then run the program again.
setenv GLOBUS_HOSTNAME ivan.evl.uic.edu
ivan.evl.uic.edu tcp_interface=184.108.40.206 udp_interface=220.127.116.11
This will tell CAVERN that when you try to establish a TCP or a UDP connection to a remote client/server running on ivan.evl.uic.edu it will use the address 18.104.22.168 rather than what the domain name server finds.
This is sometimes necessary if your computer has 2 network interfaces (one may be regular ethernet and the other maybe ATM). The ATM connection may have a different IP address than what the domain name server advertises. So this will let you use the correct IP address.
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 9000Alternatively you can do it from within the CAVERN program.
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);
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.
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.
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.
For more information look at CAVERN_irbAttrib_c, CAVERN_irbKey_c and CAVERN_irbLink_c classes. Also look at the example: demos/locking.