doc: move kernel services under kernel
Move all kernel documentation under kernel/services. Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
69d19ae9fb
commit
38635f8899
40 changed files with 132 additions and 123 deletions
228
doc/kernel/services/data_passing/pipes.rst
Normal file
228
doc/kernel/services/data_passing/pipes.rst
Normal file
|
@ -0,0 +1,228 @@
|
|||
.. _pipes_v2:
|
||||
|
||||
Pipes
|
||||
#####
|
||||
|
||||
A :dfn:`pipe` is a kernel object that allows a thread to send a byte stream
|
||||
to another thread. Pipes can be used to synchronously transfer chunks of data
|
||||
in whole or in part.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
Concepts
|
||||
********
|
||||
|
||||
The pipe can be configured with a ring buffer which holds data that has been
|
||||
sent but not yet received; alternatively, the pipe may have no ring buffer.
|
||||
|
||||
Any number of pipes can be defined (limited only by available RAM). Each pipe is
|
||||
referenced by its memory address.
|
||||
|
||||
A pipe has the following key property:
|
||||
|
||||
* A **size** that indicates the size of the pipe's ring buffer. Note that a
|
||||
size of zero defines a pipe with no ring buffer.
|
||||
|
||||
A pipe must be initialized before it can be used. The pipe is initially empty.
|
||||
|
||||
Data is synchronously **sent** either in whole or in part to a pipe by a
|
||||
thread. If the specified minimum number of bytes can not be immediately
|
||||
satisfied, then the operation will either fail immediately or attempt to send
|
||||
as many bytes as possible and then pend in the hope that the send can be
|
||||
completed later. Accepted data is either copied to the pipe's ring buffer
|
||||
or directly to the waiting reader(s).
|
||||
|
||||
Data is synchronously **received** from a pipe by a thread. If the specified
|
||||
minimum number of bytes can not be immediately satisfied, then the operation
|
||||
will either fail immediately or attempt to receive as many bytes as possible
|
||||
and then pend in the hope that the receive can be completed later. Accepted
|
||||
data is either copied from the pipe's ring buffer or directly from the
|
||||
waiting sender(s).
|
||||
|
||||
Data may also be **flushed** from a pipe by a thread. Flushing can be performed
|
||||
either on the entire pipe or on only its ring buffer. Flushing the entire pipe
|
||||
is equivalent to reading all the information in the ring buffer **and** waiting
|
||||
to be written into a giant temporary buffer which is then discarded. Flushing
|
||||
the ring buffer is equivalent to reading **only** the data in the ring buffer
|
||||
into a temporary buffer which is then discarded. Flushing the ring buffer does
|
||||
not guarantee that the ring buffer will stay empty; flushing it may allow a
|
||||
pended writer to fill the ring buffer.
|
||||
|
||||
.. note::
|
||||
Flushing does not in practice allocate or use additional buffers.
|
||||
|
||||
.. note::
|
||||
The kernel does NOT allow for an ISR to send or receive data to/from a
|
||||
pipe or flush even if it does not attempt to wait for space/data.
|
||||
|
||||
Implementation
|
||||
**************
|
||||
|
||||
A pipe is defined using a variable of type :c:struct:`k_pipe` and an
|
||||
optional character buffer of type ``unsigned char``. It must then be
|
||||
initialized by calling :c:func:`k_pipe_init`.
|
||||
|
||||
The following code defines and initializes an empty pipe that has a ring
|
||||
buffer capable of holding 100 bytes and is aligned to a 4-byte boundary.
|
||||
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
unsigned char __aligned(4) my_ring_buffer[100];
|
||||
struct k_pipe my_pipe;
|
||||
|
||||
k_pipe_init(&my_pipe, my_ring_buffer, sizeof(my_ring_buffer));
|
||||
|
||||
Alternatively, a pipe can be defined and initialized at compile time by
|
||||
calling :c:macro:`K_PIPE_DEFINE`.
|
||||
|
||||
The following code has the same effect as the code segment above. Observe
|
||||
that that macro defines both the pipe and its ring buffer.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
K_PIPE_DEFINE(my_pipe, 100, 4);
|
||||
|
||||
Writing to a Pipe
|
||||
=================
|
||||
|
||||
Data is added to a pipe by calling :c:func:`k_pipe_put`.
|
||||
|
||||
The following code builds on the example above, and uses the pipe to pass
|
||||
data from a producing thread to one or more consuming threads. If the pipe's
|
||||
ring buffer fills up because the consumers can't keep up, the producing thread
|
||||
waits for a specified amount of time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct message_header {
|
||||
...
|
||||
};
|
||||
|
||||
void producer_thread(void)
|
||||
{
|
||||
unsigned char *data;
|
||||
size_t total_size;
|
||||
size_t bytes_written;
|
||||
int rc;
|
||||
...
|
||||
|
||||
while (1) {
|
||||
/* Craft message to send in the pipe */
|
||||
data = ...;
|
||||
total_size = ...;
|
||||
|
||||
/* send data to the consumers */
|
||||
rc = k_pipe_put(&my_pipe, data, total_size, &bytes_written,
|
||||
sizeof(struct message_header), K_NO_WAIT);
|
||||
|
||||
if (rc < 0) {
|
||||
/* Incomplete message header sent */
|
||||
...
|
||||
} else if (bytes_written < total_size) {
|
||||
/* Some of the data was sent */
|
||||
...
|
||||
} else {
|
||||
/* All data sent */
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reading from a Pipe
|
||||
===================
|
||||
|
||||
Data is read from the pipe by calling :c:func:`k_pipe_get`.
|
||||
|
||||
The following code builds on the example above, and uses the pipe to
|
||||
process data items generated by one or more producing threads.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void consumer_thread(void)
|
||||
{
|
||||
unsigned char buffer[120];
|
||||
size_t bytes_read;
|
||||
struct message_header *header = (struct message_header *)buffer;
|
||||
|
||||
while (1) {
|
||||
rc = k_pipe_get(&my_pipe, buffer, sizeof(buffer), &bytes_read,
|
||||
sizeof(header), K_MSEC(100));
|
||||
|
||||
if ((rc < 0) || (bytes_read < sizeof (header))) {
|
||||
/* Incomplete message header received */
|
||||
...
|
||||
} else if (header->num_data_bytes + sizeof(header) > bytes_read) {
|
||||
/* Only some data was received */
|
||||
...
|
||||
} else {
|
||||
/* All data was received */
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Use a pipe to send streams of data between threads.
|
||||
|
||||
.. note::
|
||||
A pipe can be used to transfer long streams of data if desired. However
|
||||
it is often preferable to send pointers to large data items to avoid
|
||||
copying the data.
|
||||
|
||||
Flushing a Pipe's Buffer
|
||||
========================
|
||||
|
||||
Data is flushed from the pipe's ring buffer by calling
|
||||
:c:func:`k_pipe_buffer_flush`.
|
||||
|
||||
The following code builds on the examples above, and flushes the pipe's
|
||||
buffer.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void monitor_thread(void)
|
||||
{
|
||||
while (1) {
|
||||
...
|
||||
/* Pipe buffer contains stale data. Flush it. */
|
||||
k_pipe_buffer_flush(&my_pipe);
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
Flushing a Pipe
|
||||
===============
|
||||
|
||||
All data in the pipe is flushed by calling :c:func:`k_pipe_flush`.
|
||||
|
||||
The following code builds on the examples above, and flushes all the
|
||||
data in the pipe.
|
||||
|
||||
Suggested uses
|
||||
**************
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void monitor_thread(void)
|
||||
{
|
||||
while (1) {
|
||||
...
|
||||
/* Critical error detected. Flush the entire pipe to reset it. */
|
||||
k_pipe_flush(&my_pipe);
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
Configuration Options
|
||||
*********************
|
||||
|
||||
Related configuration options:
|
||||
|
||||
* None.
|
||||
|
||||
API Reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: pipe_apis
|
Loading…
Add table
Add a link
Reference in a new issue