# A general overview of RTAI fifos.

The new fifo implementation for RTAI maintains full compatibility with the basic services provided by its original NMT-RTL counterpart while adding many more.

It is important to remark that even if RTAI fifo APIs appears as before the implementation behind them is based on the mailbox concepts, already available in RTAI and symmetrically usable from kernel modules and Linux processes. The only notable difference, apart from the file style API functions to be used in Linux processes, is that on the module side you always have only non blocking put/get, so that any different policy should be enforced by using appropriate user handler functions.

With regard to fifo handlers it is now possible to install also one with a read/write argument (read `'r'` , write `'w'` ). In this way you have a handler that can know what it has been called for. It is useful when you open read-write fifos or to check against miscalls.

For that you can have a handler prototyped as:

    int x_handler(unsigned int fifo, int rw);

that can be installed by using:

    rtf_create_handler(fifo_numver, X_FIFO_HANDLER(x_handler));

see rtai_fifos.h for the #X_FIFO_HANDLER macro definition. The handler code is likely to be a kind of:

    int x_handler(unsigned int fifo, int rw);
    {
        if (rw == 'r') {
            // do stuff for a call from read and return appropriate value.
        } else {
            // do stuff for a call from write and return appropriate value.
        }
    }

Even if fifos are strictly no more required in RTAI, because of the availability of LXRT and LXRT-INFORMED, they are kept both for compatibility reasons and because they are very useful tools to be used to communicate with interrupt handlers, since they do not require any scheduler to be installed. In this sense you can see this new implementation of fifos as a kind of universal form of device drivers, since once you have your interrupt handler installed you can use fifo services to do all the rest.

However the new implementation made it easy to add some new services. One of these is the possibility of using asyncronous signals to notify data availability by catching a user set signal. It is implemented in a standard way, see the function:

    rtf_set_async_sig(int fd, int signum) (default signum is SIGIO);

and standard Linux man for fcntl and signal/sigaction, while the others are specific to this implementation.

A complete picture of what is available can be obtained from a look at rtai_fifos.h prototypes.

It is important to remark that now fifos allows multiple readers/writers so the select/poll mechanism to synchronize with in/out data can lead to unexpected blocks for such cases. For example: you poll and get that there are data available, then read/write them sure not to be blocked, meanwhile another user gets into and stoles all of your data, when you ask for them you get blocked.

To avoid such problems you have available the functions:

    rtf_read_all_at_once(fd, buf, count);

that blocks till all count bytes are available;

    rtf_read_timed(fd, buf, count, ms_delay);

    rtf_write_timed(fd, buf, count, ms_delay);

that block just for the specified delay in milliseconds but are queued in real time Linux process priority order. If ms_delay is zero they return immediately with all the data they could get, even if you did not set `O_NONBLOCK` at fifo opening.

So by mixing normal read/writes with their friends above you can easily implement blocking, non blocking and timed IOs. They are not standard and so not portable, but far easy to use then the select/poll mechanism. The standard llseek is also available but it is equivalent to calling rtf_reset, whatever fifo place you point at in the call.

For an easier timing you have available also:

    rtf_suspend_timed(fd, ms_delay).

To make them easier to use, fifos can now be created by the user at open time. If a fifo that does not exist already is opened, it is created with a 1K buffer. Any following creation on modules side resizes it without any loss of data. Again if you want to create a fifo from the user side with a desired buffer size you can use:

    rtf_open_sized(const char *dev, perm, size).

Since they had to be there already to implement our mailboxes we have made available also binary semaphores. They can be used for many things, e.g. to synchronize shared memory access without any scheduler installed and in place of using blocking fifos read/writes with dummy data, just to synchronize. The semaphore services available are:

    rtf_sem_init(fd, init_val);

    rtf_sem_wait(fd);

    rtf_sem_trywait(fd);

    rtf_sem_timed_wait(fd, ms_delay);

    rtf_sem_post(fd);

    rtf_sem_destroy(fd);

Note that fd is the file descriptor, a semaphore is always associated to a fifo and you must get a file descriptor by opening the corresponding fifo.

Naturally the above functions are symmetrically available in kernel space but, except for init and create, only for the nonblocking services, i.e: trywait and post.