rb_posix_read(3)

bofc manual pages

rb_posix_read(3)



 

NAME

rb_posix_read, rb_posix_recv - functions to directly send data from ring buffer to object associated with file descriptor.  

SYNOPSIS

#include <librb.h>

long rb_posix_read(struct rb *rb, int fd, size_t count);
long rb_posix_recv(struct rb *rb, int fd, size_t count, unsigned long flags);

Feature Test Macro:

rb_posix_read(), rb_posix_recv():

ENABLE_POSIX_CALLS
 

DESCRIPTION

rb_posix_read(3) copies at most count bytes from ring buffer rb to object associated with fd file descriptor.

rb_posix_read(3) works in the same way as rb_read(3) but instead of copying data to buffer it copies data to whatever is pointed by fd file descriptor. This may be ordinary file on disk, or pipe, or serial device, or network socket. This is convenient function that may be useful when constructing packet frame to send. You could first prepare packet byte by byte with rb_write(3) and then send whole packet with rb_posix_read(3) function in on single burst. Calling multiple rb_write(3) followed by single rb_posix_read(3) to send frame, will be way faster than calling multiple write() system call functions.

Another change is that while ordinary rb_read (3) works on elements, rb_posix_read (3) works solely on bytes and thus rb object must be created with object_size set to 1 or these functions will return EINVAL error. This is due to the fact, that rb uses write() under the hood which works on bytes. Reason for such limitation is that write() may return after writing two and a half of object size and second half of third object would be lost causing mayheem in communication stream. Fixing that would require blocking calling thread and rb cannot make that such decision for the user. So if you want to send 5 frames of data in one call, you need to do rb_posix_read(rb, fd, 5 * sizeof(data_frame)).

rb_posix_recv(3) work the same as rb_posix_read(3) but it also accepts flags. Possible flags are:

MSG_DONTWAIT
Only works in multi threaded environment, on single threaded mode this is default. When passed and rb contains less bytes than passed in count, function will copy all bytes from rb into fd and will return immediately. This means, function will never block, no matter what. Not recommended when multiple threads calls rb_read(3) with this flag - may lead to interlaced reads
MSG_PEEK
Reads from rb into fd as normal, but doesn't remove data from rb, so consecutive calls to this function will return same data (provided that nobody called rb_posix_recv(3) without this flag). When this is called in threaded environment enabled, functions will act as if MSG_DONTWAIT flag was also passed. It is guaranteed that calling function with this flag, will not alter internal state of rbobject.
 

EXAMPLE

Reading frames by multiple parsers. Error handling ommited for clarity. rb object is assumed to be created with object_size equals to 1.


    void *parser(void *arg)
    {
        struct rb *rb = arg;


        for (;;)
        {
            struct frame f;


            /* when rb was created with O_MULTITHREAD, this function
             * is guaranteed to store exactly sizeof(f) data, and
             * this data will be continous, that is no other parser
             * thread will wake up, and take any byte in the middle
             * of our read (that is if rb_read doesn't return -1)
             */


            if (rb_read(rb, &f, sizeof(f)) == -1)
            {
                if (errno == ECANCELED)
                {
                    /* rb_stop() has been called, rb object should
                     * not be used any more
                     */


                    break;
                }


                /* some other error */
            }


            /* f object will be valid here, some frame processing
             * stuff can be made here
             */
        }


        /* perform cleanup */
        return NULL;
    }


    void loop(struct rb *rb)
    {
        int fd, i;
        pthread_t parsers[4];


        fd = init_client_socket();


        for(i = 0; i != 4; ++i)
        {
            /* create parser threads, they will block in rb_read()
             * as we didn't put any data to rb yet
             */


            pthread_create(&parsers[i], NULL, parse, rb);
        }


        for (;;)
        {
            /* read data from fd socket and write them to rb
             * for further processing, we set count to max
             * value for performance as we don't need it to
             * return (unless error occurs)
             *
             * NOTE: rb will now be locked from writing, only
             * this thread will be able to write to rb, don't
             * try to call another rb_write() function, it will
             * be blocked until this function returns - and it
             * may take a while to read LONG_MAX bytes.
             *
             * LONG_MAX is passed as count because we want this
             * function to be called as rarely as possible, and
             * still we don't want to overflow internal integer.
             *
             * You could also pass '-1' here, it would be casted
             * to unsigned type and the it would be reduced to
             * LONG_MAX anyway.
             */


            if (rb_posix_write(rb, fd, LONG_MAX) == -1)
            {
                if (errno == ECANCELED)
                {
                    /* rb_stop() has been called, we shouldn't
                     * use rb object anymore
                     */


                    break;
                }
            }
        }


        for (i = 0; i != 4; ++i)
        {
            /* join all parsers, so rb_destory() can be safely
             * called
             */


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

RETURN VALUES

On successfull read, function will return number of bytes it read from rb object and stored in fd file descriptor. Returned value can be less than count if rb doesn't contain enough data and function operates in non blocking mode. On errors function returns -1, in such case, rb is left intact.  

ERRORS

EINVAL
Any of the passed pointers is NULL. EINVAL rb_posix_read(3) was called when 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 data to be read from rb immediately.
ECANCELED
rb_stop(3) was called, and operation was cancelled, because rb object is about 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_write(3), rb_send(3), rb_posix_write(3), rb_posix_send(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_read(3)