REQUIREMENTS You need an installed and running RTLinux. This version has been tested with RTLinux-3.1. It may also run with RTAI, but I haven't tried yet. You also need an installed and running version of ROOT. I've tried hard with 3.03-9, but there seems to be a bug, so that Trees are not working very well. But 3.03-8 works fine with this package. I recommend compiling ROOT with thread support, so you can use the thread related classes of this package and analyse the tree while it is filled from your RTLinux application. During my tests ROOT was compiled for linuxdeb with thread support. OVERVIEW A RTLinux application running in Kernel-Space can't access ROOT-Trees in UserSpace directly. The only interfaces between User- and Kernel-Space are FIFOs and shared memory. So one could set the Branch-Variable of a Tree in shared memory, write data into it from Kernel-Space and fill the Tree from User-Space. But this approach has a disadvantage: it is not predictable, when ROOT gets time from the scheduler and can fill the tree. In some situations RTLinux may write the data many times without ROOT having time to handle it. So data is lost. This package consists of two parts: 1. A kernel module for RTLinux which provides a little API for Tree access. The commands and the corresponding data is written to a FIFO. 2. Some ROOT-classes which read the stream of commands and data, interpret it and finally execute the corresponding Tree functionality. Please note that RTLinux applications will only write the data and commands to a buffer. The real work is done with lowest priority by ROOT in User-Space! how it works internally (an example) void roottree_setbranch(char* tree,char *branch,void * data,int count); calling this funtion from a rtlinux application will write the command and the related data to the fifo. On the User-Space side ROOT will get a pointer to the tree by calling TTree*t=file->Get(tree). By default file is the same as gFile. Now ROOT can get the branch by means of TBranch *b=t->GetBranch(). Finally b->GetAddress() is the address of the branch variable. This variable is now set by copying the data to to it. Since RTLinux doesn't know the size of your Branch variable you have to explicity tell it in the function. If you want to write to a Branch variable of the type TDaten, you can do so: struct TDaten data; ... roottree_setbranch("mytree","mybranch",&data,sizeof(struct TDaten)); Make sure, that TDaten is the same in User- and Kernel-Space. (and has the same size) other commands are: void roottree_fill(char * tree); perfoms a tree->Fill(); in User-Space void roottree_write(char * tree); accordingly a tree->Write(); A QUICK WALKTHROUGH The ROOT-classes were designed for use in your own measurement aquisition programs or daemons. But testing works fine from within the ROOT-Interpreter. (But the ROOT-Interpreter #defines all private and protected tags to public. So maybe the latest version may not be compiled from outside, since I always want to be as strict as possible and maybe I've forgotten something. In this case simply move the method/variable to public or protected and write a short email to me please) So, lets start with the RTLinux module. 1. Boot into your RTLinux Kernel and start the modules according to the manual (starting scripts by calling scripts/insrtl from within your RTLinux Installation) 2. unzip this package and cd to rtltree/rtlinux. Copy rtl.mk from your RTLinux Installation to this directory. 3. compile the rtltree module: make -f rtl.mk rttree.o 4. compile the test application make -f rtl.mk test.o 5. (as root) load the rtltree-module: insmod insmod rttree.o Now, lets start the root-part 1. cd to rtltree/root 2. start root. you will get a lot of errors since to librarys used in rootlogon.C have not been compiled yet. 3. compile the classes with ACLiC: .L RTLTreeWatcher.C+ .L RTLThreadTree.C+ .L RTLThreadTreeWatcher.C+ 4. quit ROOT and start it again. You should now see something like "ROOT Watching on RTLinux". If you get the error "Exception caught:Cannot open RTL-FIFO" make sure you have loaded the kernel module properly. Press return, you should be able to use ROOT as usual. 5. RTLinux can only access existing TTrees in a given file. This is gFile by default. So you have to create a TTree. There is a macro which creates a testing TFile and a TTree with a branch for the test.o application. Start it with .x TreeTest.C. 6. The rtltree package can also handle ordinary TTrees. But if you want to have access to the TTress during data aquisition you need a locking mechanism, otherwise you will run into big trouble when the TTree is changed while you are accessing it. So there is an extension to TTrees which provides a lockin mechanism. You can get access to the RTLThreadTree by typing: RTLThreadTree *t=gFile->Get("mytree") 7. Try t->Lock(); t->Scan(); t->UnLock() you will see an empty Tree. From the rtltree/rtlinux directory (as root) you can start the test application: insmod test.o (don't leave ROOT) Now try t->Lock(); t->Scan(); t->UnLock() from within ROOT again some times and you can see how the Tree is filled. You can stop the test by unloading the module: rmmod test DETAILS ON THE KERNEL MODULE RTLinux communicates with ROOT via a FIFO. By default, FIFO 0 is used. If you use this number for your own needs, you can change the used number when loading the rttree module: insmod rttree.o roottree_fifo=xx Your RTLinux application writes data to the FIFO buffer. If you lock a RTLThreadTree in User-Space for a long time, the buffer may overrun. To prevent this, you can set the buffer-size. The default is 4096 and quite small: insmod rttree.o roottree_fifo_size=8192 Look into rttree.h to see the quite small API. The first 3 command will work with any combination of TTree, RTLThreadTree, RTLTreeWatcher and RTLThreadTreeWatcher in User-Space The last two locking commands work only if you use RTLThreadTree and RTLThreadTreeWatcher. Please keep in mind, that no locking is performed in Kernel-Space! Locking takes only place in User-Space! DETAILS ON THE ROOT CLASSES The RTL...Watcher classes are reading the stream from the FIFO and doing the real work. They both can handle TTrees. The main difference is that RTLTreeWatcher doesnt't return when calling the watch() method. RTLThreadTreeWatcher instead starts a seperate thread which does the work and returns almost immediately. If you use RTLThreadTrees instead of TTrees the RTLThreadTreeWatcher can lock/unlock them if your RTLinux application demands this for a setbranch/fill sequence. If you do it in your data analysis too, you can use the RTLThreadTree during it is filled by RTLinux. But never access the Tree or make suggestion about the Branch-Variables, when it is unlocked!!! And don't lock it over long periods, otherwise your buffer may overrun. Let's take a short look on the constructor: RTLTreeWatcher(char *fifo="/dev/rtf0",TFile *f=gFile); In most cases, you can use the default values. If you used another fifo when loading the kernel module, use the same here. If you want a special TFile where your Trees should be accessed, mention it here. If you call the constructor when gFile is still NULL, it won't matter. But you have to be sure that it is not NULL when the first RTLinux command arrives. TODO In this version the whole errorhandling is performed in User-Space. RTLinux application will never know when something went wrong. This is, because the commands must be performed in realtime. It could take a long time until ROOT has time to do the real work and send back any errors. It is no good idea to block a RTLinux Thread and wait for an answer from ROOT... But an asynchrous callback mechanism may be possible. This will be done in the next version. Creating Trees and Branches (and Branch Variables!!!) from within RTLinux may also be desireable. Oliver.Kuehlert@mpi-hd.mpg.de