diff options
author | Allan Stephens <allan.stephens@windriver.com> | 2016-10-19 10:26:56 -0500 |
---|---|---|
committer | Benjamin Walsh <benjamin.walsh@windriver.com> | 2016-10-21 15:33:31 +0000 |
commit | 11a1bb4125329c065720554fcaa23328f24997ba (patch) | |
tree | 65dfb2631bb87b0f78269209489b9a5d138061c8 /doc | |
parent | b9a4bd906c8b4d6edbc8cbd94668bde7fdcb71ca (diff) |
unified/doc: Update ring buffers section of Kernel Primer
Ring buffer section now resides under "other" topic, since the
ring buffer type is a general purpose type (like the singly and
doubly linked list types), rather than a kernel-specific type.
Enhances ring buffer section to improve content and improve
consistency with the form used elsewhere in the Kernel Primer.
Also corrects a minor error in the ring buffer API documentation.
Change-Id: Icaa8661524f80e31f173adee859844cadb38967f
Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Diffstat (limited to 'doc')
-rw-r--r-- | doc/kernel_v2/data_passing/data_passing.rst | 1 | ||||
-rw-r--r-- | doc/kernel_v2/data_passing/ring_buffers.rst | 143 | ||||
-rw-r--r-- | doc/kernel_v2/other/other.rst | 1 | ||||
-rw-r--r-- | doc/kernel_v2/other/ring_buffers.rst | 184 |
4 files changed, 185 insertions, 144 deletions
diff --git a/doc/kernel_v2/data_passing/data_passing.rst b/doc/kernel_v2/data_passing/data_passing.rst index 6ba38a72b..cae29b9ea 100644 --- a/doc/kernel_v2/data_passing/data_passing.rst +++ b/doc/kernel_v2/data_passing/data_passing.rst @@ -13,6 +13,5 @@ between different threads, or between an ISR and a thread. lifos.rst stacks.rst message_queues.rst - ring_buffers.rst mailboxes.rst pipes.rst diff --git a/doc/kernel_v2/data_passing/ring_buffers.rst b/doc/kernel_v2/data_passing/ring_buffers.rst deleted file mode 100644 index ca0b63a96..000000000 --- a/doc/kernel_v2/data_passing/ring_buffers.rst +++ /dev/null @@ -1,143 +0,0 @@ -.. _ring_buffers_v2: - -Ring Buffers [TBD] -################## - -Definition -********** - -The ring buffer is defined in :file:`include/misc/ring_buffer.h` and -:file:`kernel/nanokernel/ring_buffer.c`. This is an array-based -circular buffer, stored in first-in-first-out order. The APIs allow -for enqueueing and retrieval of chunks of data up to 1024 bytes in size, -along with two metadata values (type ID and an app-specific integer). - -Unlike nanokernel FIFOs, storage of enqueued items and their metadata -is managed in a fixed buffer and there are no preconditions on the data -enqueued (other than the size limit). Since the size annotation is only -an 8-bit value, sizes are expressed in terms of 32-bit chunks. - -Internally, the ring buffer always maintains an empty 32-bit block in the -buffer to distinguish between empty and full buffers. Any given entry -in the buffer will use a 32-bit block for metadata plus any data attached. -If the size of the buffer array is a power of two, the ring buffer will -use more efficient masking instead of expensive modulo operations to -maintain itself. - -Concurrency -*********** - -Concurrency control of ring buffers is not implemented at this level. -Depending on usage (particularly with respect to number of concurrent -readers/writers) applications may need to protect the ring buffer with -mutexes and/or use semaphores to notify consumers that there is data to -read. - -For the trivial case of one producer and one consumer, concurrency -shouldn't be needed. - -Example: Initializing a Ring Buffer -=================================== - -There are three ways to initialize a ring buffer. The first two are through use -of macros which defines one (and an associated private buffer) in file scope. -You can declare a fast ring buffer that uses mask operations by declaring -a power-of-two sized buffer: - -.. code-block:: c - - /* Buffer with 2^8 or 256 elements */ - SYS_RING_BUF_DECLARE_POW2(my_ring_buf, 8); - -Arbitrary-sized buffers may also be declared with a different macro, but -these will always be slower due to use of modulo operations: - -.. code-block:: c - - #define MY_RING_BUF_SIZE 93 - SYS_RING_BUF_DECLARE_SIZE(my_ring_buf, MY_RING_BUF_SIZE); - -Alternatively, a ring buffer may be initialized manually. Whether the buffer -will use modulo or mask operations will be detected automatically: - -.. code-block:: c - - #define MY_RING_BUF_SIZE 64 - - struct my_struct { - struct ring_buffer rb; - uint32_t buffer[MY_RING_BUF_SIZE]; - ... - }; - struct my_struct ms; - - void init_my_struct { - sys_ring_buf_init(&ms.rb, sizeof(ms.buffer), ms.buffer); - ... - } - -Example: Enqueuing data -======================= - -.. code-block:: c - - int ret; - - ret = sys_ring_buf_put(&ring_buf, TYPE_FOO, 0, &my_foo, SIZE32_OF(my_foo)); - if (ret == -EMSGSIZE) { - ... not enough room for the message .. - } - -If the type or value fields are sufficient, the data pointer and size may be 0. - -.. code-block:: c - - int ret; - - ret = sys_ring_buf_put(&ring_buf, TYPE_BAR, 17, NULL, 0); - if (ret == -EMSGSIZE) { - ... not enough room for the message .. - } - -Example: Retrieving data -======================== - -.. code-block:: c - - int ret; - uint32_t data[6]; - - size = SIZE32_OF(data); - ret = sys_ring_buf_get(&ring_buf, &type, &value, data, &size); - if (ret == -EMSGSIZE) { - printk("Buffer is too small, need %d uint32_t\n", size); - } else if (ret == -EAGAIN) { - printk("Ring buffer is empty\n"); - } else { - printk("got item of type %u value &u of size %u dwords\n", - type, value, size); - ... - } - -APIs -**** - -The following APIs for ring buffers are provided by :file:`ring_buffer.h`: - -:cpp:func:`sys_ring_buf_init()` - Initializes a ring buffer. - -:c:func:`SYS_RING_BUF_DECLARE_POW2()`, :c:func:`SYS_RING_BUF_DECLARE_SIZE()` - Declare and init a file-scope ring buffer. - -:cpp:func:`sys_ring_buf_space_get()` - Returns the amount of free buffer storage space in 32-bit dwords. - -:cpp:func:`sys_ring_buf_is_empty()` - Indicates whether a buffer is empty. - -:cpp:func:`sys_ring_buf_put()` - Enqueues an item. - -:cpp:func:`sys_ring_buf_get()` - De-queues an item. diff --git a/doc/kernel_v2/other/other.rst b/doc/kernel_v2/other/other.rst index 47f189430..c1479a031 100644 --- a/doc/kernel_v2/other/other.rst +++ b/doc/kernel_v2/other/other.rst @@ -10,6 +10,7 @@ This section describes other services provided by the kernel. atomic.rst float.rst + ring_buffers.rst event_logger.rst c_library.rst cxx_support.rst diff --git a/doc/kernel_v2/other/ring_buffers.rst b/doc/kernel_v2/other/ring_buffers.rst new file mode 100644 index 000000000..2d4025f14 --- /dev/null +++ b/doc/kernel_v2/other/ring_buffers.rst @@ -0,0 +1,184 @@ +.. _ring_buffers_v2: + +Ring Buffers +############ + +A :dfn:`ring buffer` is a circular buffer of 32-bit words, whose contents +are stored in first-in-first-out order. Data items can be enqueued and dequeued +from a ring buffer in chunks of up to 1020 bytes. Each data item also has +two associated metadata values: a type identifier and a 16-bit integer value, +both of which are application-specific. + +.. contents:: + :local: + :depth: 2 + +Concepts +******** + +Any number of ring buffers can be defined. Each ring buffer is referenced +by its memory address. + +A ring buffer has the following key properties: + +* A **data buffer** of 32-bit words. The data buffer contains the data items + that have been added to the ring buffer but not yet removed. + +* A **data buffer size**, measured in 32-bit words. This governs the maximum + amount of data (including metadata values) the ring buffer can hold. + +A ring buffer must be initialized before it can be used. This sets its +data buffer to empty. + +A ring buffer **data item** is an array of 32-bit words from 0 to 1020 bytes +in length. When a data item is **enqueued** its contents are copied +to the data buffer, along with its associated metadata values (which occupy +one additional 32-bit word). +If the ring buffer has insufficient space to hold the new data item +the enqueue operation fails. + +A data items is **dequeued** from a ring buffer by removing the oldest +enqueued item. The contents of the dequeued data item, as well as its +two metadata values, are copied to areas supplied by the retriever. +If the ring buffer is empty, or if the data array supplied by the retriever +is not large enough to hold the data item's data, the dequeue operation fails. + +Concurrency +=========== + +The ring buffer APIs do not provide any concurrency control. +Depending on usage (particularly with respect to number of concurrent +readers/writers) applications may need to protect the ring buffer with +mutexes and/or use semaphores to notify consumers that there is data to +read. + +For the trivial case of one producer and one consumer, concurrency +shouldn't be needed. + +Internal Operation +================== + +The ring buffer always maintains an empty 32-bit word in its data buffer +to allow it to distinguish between empty and full states. + +If the size of the data buffer is a power of two, the ring buffer +uses efficient masking operations instead of expensive modulo operations +when enqueuing and dequeuing data items. + +Implementation +************** + +Defining a Ring Buffer +====================== + +A ring buffer is defined using a variable of type :c:type:`struct ring_buf`. +It must then be initialized by calling :cpp:func:`sys_ring_buf_init()`. + +The following code defines and initializes an empty ring buffer +(which is part of a larger data structure). The ring buffer's data buffer +is capable of holding 64 words of data and metadata information. + +.. code-block:: c + + #define MY_RING_BUF_SIZE 64 + + struct my_struct { + struct ring_buffer rb; + uint32_t buffer[MY_RING_BUF_SIZE]; + ... + }; + struct my_struct ms; + + void init_my_struct { + sys_ring_buf_init(&ms.rb, sizeof(ms.buffer), ms.buffer); + ... + } + +Alternatively, a ring buffer can be defined and initialized at compile time +using one of two macros at file scope. Each macro defines both the ring +buffer itself and its data buffer. + +The following code defines a ring buffer with a power-of-two sized data buffer, +which can be accessed using efficient masking operations. + +.. code-block:: c + + /* Buffer with 2^8 (or 256) words */ + SYS_RING_BUF_DECLARE_POW2(my_ring_buf, 8); + +The following code defines a ring buffer with an arbitraty-sized data buffer, +which can be accessed using less efficient modulo operations. + +.. code-block:: c + + #define MY_RING_BUF_WORDS 93 + SYS_RING_BUF_DECLARE_SIZE(my_ring_buf, MY_RING_BUF_WORDS); + +Enqueuing Data +============== + +A data item is added to a ring buffer by calling :cpp:func:`sys_ring_buf_put()`. + +.. code-block:: c + + uint32_t my_data[MY_DATA_WORDS]; + int ret; + + ret = sys_ring_buf_put(&ring_buf, TYPE_FOO, 0, my_data, SIZE32_OF(my_data)); + if (ret == -EMSGSIZE) { + /* not enough room for the data item */ + ... + } + +If the data item requires only the type or application-specific integer value +(i.e. it has no data array), a size of 0 and data pointer of :c:macro:`NULL` +can be specified. + +.. code-block:: c + + int ret; + + ret = sys_ring_buf_put(&ring_buf, TYPE_BAR, 17, NULL, 0); + if (ret == -EMSGSIZE) { + /* not enough room for the data item */ + ... + } + +Retrieving Data +=============== + +A data item is removed from a ring buffer by calling +:cpp:func:`sys_ring_buf_get()`. + +.. code-block:: c + + uint32_t my_data[MY_DATA_WORDS]; + uint16_t my_type; + uint8_t my_value; + uint8_t my_size; + int ret; + + my_size = SIZE32_OF(my_data); + ret = sys_ring_buf_get(&ring_buf, &my_type, &my_value, my_data, &my_size); + if (ret == -EMSGSIZE) { + printk("Buffer is too small, need %d uint32_t\n", my_size); + } else if (ret == -EAGAIN) { + printk("Ring buffer is empty\n"); + } else { + printk("Got item of type %u value &u of size %u dwords\n", + my_type, my_value, my_size); + ... + } + +APIs +**** + +The following ring buffer APIs are provided by :file:`misc/ring_buffer.h`: + +* :c:func:`SYS_RING_BUF_DECLARE_POW2()` +* :c:func:`SYS_RING_BUF_DECLARE_SIZE()` +* :cpp:func:`sys_ring_buf_init()` +* :cpp:func:`sys_ring_buf_is_empty()` +* :cpp:func:`sys_ring_buf_space_get()` +* :cpp:func:`sys_ring_buf_put()` +* :cpp:func:`sys_ring_buf_get()` |