rb_posix_write(3)

bofc manual pages

rb_posix_write(3)



 

NAME

rb_posix_write, rb_posix_send - functions to put data on ring buffer directly from object associated with file descriptor  

SYNOPSIS

#include <librb.h>

long rb_posix_write(struct rb *rb, int fd, size_t count);
long rb_posix_send(struct rb *rb, int fd, size_t count, unsigned long flags);

Feature Test Macro:

rb_posix_write(), rb_posix_send():

ENABLE_POSIX_CALLS
 

DESCRIPTION

rb_posix_write(3) copies at most count bytes from fd to rb.

rb_posix_write(3) works in the same way as rb_write(3) but instead of copying data from buffer to rb object, it will copy data from whatever is associated with fd file descriptor to rb object. This may be ordinary file on disk, or pipe, or seria ldevice, or network socket. This is convenient function that may be useful when you want to read same frame from multiple sources - like allowing to control embedded device via serial, network and fifo simultaneously. For example you can create 3 threads that will read data to rb and then one thread that will parse it. This way you can get rid of polling each interface for data, which will speed up execution - check example below.

Another change is that while ordinary rb_write(3) works on elements, rb_posix_write(3) works solely on bytes and thus rb object must be created with object_size set to 1 or these function will return EINVAL error. This is due to the fact that rb uses read() under the hood which works on bytes. Reason for such limitaion is that read() may return after reading two and a half of object size and you would end up having 2 halfs of one frame stored as 2 separated frames. Fixing that would rquire blocking calling thread and rb cannot make such decision for the user. So if you want to read 5 frames of data in one call into rb you need to do rb_posix_write(rb, fd, 5 * sizeof(data_frame)).

It is valid for rb_posix_write(3) to make early return with return value less than count bytes. This will happen when internal write() returns zero, which may mean we read end of the file, or remote computer closed network connection.

rb_posix_send(3) work the same way as rb_posix_write(3) but also accept following flags:

MSG_DONTWAIT
Only works in multi threaded environment, on single threaded mode this is default. When passed and rb contains less free bytes than passed in count, function will copy all bytes from fd into rb and will return immediately. Not recommended when multiple concurent threads calls rb_posix_write(3) with this flag - may lead to interlaced reads.
 

EXAMPLE

Reading frames from multiple sockets and parse them in one thread. As usual, error handling ommited for clarity. It is assumend that rb was created with object_size equal to 1.


    struct tdata
    {
        struct rb *rb;
        int fd;
    };


    void *receiver(void *arg)
    {
        struct tdata *data = arg;


        for (;;)
        {
            /* rb_posix_write() will sleep current thread until
             * data shows up on data->fd file descriptor.
             *
             * NOTE: you should be carefull here, as calling this
             * function on slow data->fd will block other threads.
             * rb will try to call read() on data->fd and read()
             * will block until any data shows on data->fd, and
             * if data->fd is slow, this may take a long time.
             */


            if (rb_posix_write(data->rb, data->fd,
                    sizeof(struct data_frame) == -1)
            {
                if (errno == ECANCELED)
                {
                    /* rb_stop() has been called, rb shouldn't
                     * be used any more
                     */
                    break;
                }


                /* some other error */
            }
        }
    }


    void loop(struct rb *rb)
    {
        struct tdata tdata[3];
        pthread_t receivers[3];
        int i;


        tdata[0].rb = rb;
        tdata[0].fd = get_network_socket();


        tdata[1].rb = rb;
        tdata[1].fd = get_serial_socket();


        tdata[2].rb = rb;
        tdata[2].fd = get_fifo_socket();


        for (i = 0; i != 3; ++i)
        {
            /* create multiple threads that will read data from
             * sockets and put that data into rb. Pretty nice
             * way to eliminate polling, as these threads will
             * wake only when there is data available
             /


            pthread_create(&receivers[i], NULL, receiver, &tdata[i]);
        }


        for (;;)
        {
            /* receivers are started and will populate our rb with
             * frames over time, rb guarantees all frames here will
             * be valid (if they come valid from socket that is)
             */


            struct data_frame f;


            if (rb_read(rb, &f, sizeof(f)) == -1)
            {
                if (errno == ECANCELED)
                {
                    /* rb_stop() has been called, we shouldn't
                     * use rb object anymore
                     */


                    break;
                }
            }


            process_frame(&f);
        }


        for (i = 0; i != 3; ++i)
        {
            /* join all threads using rb object, so rb_destroy()
             * can be called safely
             */


            pthread_join(receivers[i], NULL);
        }
    }

 

RETURN VALUES

On successfull write, function will return number of bytes it stored in rb. Returned value can be less than count if rb doesn't contain enough free space and function operates in non blocking mode. It is also possible that internal read() returned 0 (end of file or remote client closed network socket), in which case function will also return. It's also possible for these functions to return 0 in case when read() returned 0 and not data has been commited to rb. On errors function returns -1, in such case, rb is left intact.  

ERRORS

EINVAL
Any of the passed pointers is NULL
EINVAL
rb object was created with object_size different than 1.
EAGAIN
This error will be set, when rb is operating in non blocking mode, and there is no place in rb to write data from fd immediately.
ECANCELED
rb_stop(3) was called, and operation was cancelled, because rb object is abou to be destroyed. You should not access rb object after you receive this error. Otherwise you will probably get deadlock or application will crash. Returned only if threads are enabled.
ENOSYS
Function is not implemented (was not compiled in).
 

SEE ALSO

rb_overview(7), rb_new(3), rb_init(3), rb_destroy(3), rb_cleanup(3), rb_discard(3), rb_stop(3), rb_stop_signal(3), rb_read(3), rb_recv(3), rb_posix_read(3), rb_posix_recv(3), rb_clear(3), rb_count(3), rb_space(3), rb_header_size(3), rb_array_size(3), rb_version(3)

bofc.pl

23 October 2018 (v1.1.0)

rb_posix_write(3)