Skip to content

Commit

Permalink
doc: Minor corrections to kernel API documentation
Browse files Browse the repository at this point in the history
Addresses a range of issues affecting the Kernel Primer or
the API Guide generated from doxygen tags.

* Ensures mailbox examples use kernel APIs correctly.
  (Fix for ZEP-1262, as well as other errors).

* Ensures memory alignment limitations for memory slabs
  are correctly described. (Fix for ZEP-1265.)

* Ensures memory alignment limitations for memory pools
  are more clearly described. Also fixes a typo in a
  memory pool example.

* Ensures memory alignment limitations for message
  queues are more clearly described.

* Fixes references to a number of kernel configuration
  options that were omitted or incorrectly formatted.

* Fixes a typo in an example of thread spawning.

Change-Id: I395186f333490b1e0c4223b87c0fe7136548770f
Signed-off-by: Allan Stephens <[email protected]>
  • Loading branch information
ajstephens authored and Anas Nashif committed Nov 11, 2016
1 parent add6e00 commit da82722
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 36 deletions.
28 changes: 18 additions & 10 deletions doc/kernel_v2/data_passing/mailboxes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,19 @@ to hold off the sending of a new message until the previous message
has been consumed, so that a backlog of messages doesn't build up
when the consuming thread is unable to keep up.

The message data is stored in a memory block obtained from ``TXPOOL``,
The message data is stored in a memory block obtained from a memory pool,
thereby eliminating unneeded data copying when exchanging large messages.
The memory pool contains only two blocks: one block gets filled with
data while the previously sent block is being processed

.. code-block:: c
/* define a semaphore, indicating that no message has been sent */
K_SEM_DEFINE(my_sem, 1, 1);
/* define a memory pool containing 2 blocks of 4096 bytes */
K_MEM_POOL_DEFINE(my_pool, 4096, 4096, 2, 4);
void producer_thread(void)
{
struct k_mbox_msg send_msg;
Expand All @@ -334,20 +339,20 @@ thereby eliminating unneeded data copying when exchanging large messages.
while (1) {
/* allocate a memory block to hold the message data */
k_mem_pool_alloc(&send_msg.tx_block, TXPOOL, 4096, K_FOREVER);
k_mem_pool_alloc(&mp_pool, &send_msg.tx_block, 4096, K_FOREVER);
/* keep overwriting the hardware-generated data in the block */
/* until the previous message has been received by the consumer */
do {
memcpy(send_msg.tx_block.pointer_to_data, hw_buffer, 4096);
memcpy(send_msg.tx_block.data, hw_buffer, 4096);
} while (k_sem_take(&my_sem, K_NO_WAIT) != 0);
/* finish preparing to send message */
send_msg.size = 4096;
send_msg.rx_target_thread = K_ANY;
send_msg.tx_target_thread = K_ANY;
/* send message containing most current data and loop around */
k_mbox_async_put(&my_mailbox, &send_msg, MY_SEMA);
k_mbox_async_put(&my_mailbox, &send_msg, &my_sem);
}
}
Expand Down Expand Up @@ -570,6 +575,9 @@ thereby eliminating unneeded data copying when processing a large message.

.. code-block:: c
/* define a memory pool containing 1 block of 10000 bytes */
K_MEM_POOL_DEFINE(my_pool, 10000, 10000, 1, 4);
void consumer_thread(void)
{
struct k_mbox_msg recv_msg;
Expand All @@ -588,11 +596,11 @@ thereby eliminating unneeded data copying when processing a large message.
k_mbox_get(&my_mailbox, &recv_msg, NULL, K_FOREVER);
/* get message data as a memory block and discard message */
k_mbox_data_block_get(&recv_msg, RXPOOL, &recv_block, K_FOREVER);
k_mbox_data_block_get(&recv_msg, &my_pool, &recv_block, K_FOREVER);
/* compute sum of all message bytes in memory block */
total = 0;
data_ptr = (char *)(recv_block.pointer_to_data);
data_ptr = (char *)(recv_block.data);
for (i = 0; i < recv_msg.size; i++) {
total += data_ptr++;
}
Expand All @@ -604,9 +612,9 @@ thereby eliminating unneeded data copying when processing a large message.
.. note::
An incoming message that was sent using a message buffer is also processed
correctly by this algorithm, since the mailbox automatically creates
a memory block containing the message data using ``RXPOOL``. However,
the performance benefit of using the memory block approach is lost.
correctly by this algorithm, since the mailbox automatically allocates
a memory block from the memory pool and fills it with the message data.
However, the performance benefit of using the memory block approach is lost.

Suggested Uses
**************
Expand Down
18 changes: 12 additions & 6 deletions doc/kernel_v2/data_passing/message_queues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@ by its memory address.

A message queue has the following key properties:

* A **queue** of data items that have been sent but not yet received.
The queue is implemented using a ring buffer.
* A **ring buffer** of data items that have been sent but not yet received.

* The **data item size**, measured in bytes, of each data item.
* A **data item size**, measured in bytes.

* A **maximum quantity** of data items that can be queued in the ring buffer.

The message queue's ring buffer must be aligned to an N-byte boundary, where
N is a power of 2 (i.e. 1, 2, 4, 8, ...). To ensure that the messages stored in
the ring buffer are similarly aligned to this boundary, the data item size
must also be a multiple of N.

A message queue must be initialized before it can be used.
This sets its queue to empty.
This sets its ring buffer to empty.

A data item can be **sent** to a message queue by a thread or an ISR.
The data item a pointed at by the sending thread is copied to a waiting thread,
Expand Down Expand Up @@ -65,12 +69,14 @@ A message queue is defined using a variable of type :c:type:`struct k_msgq`.
It must then be initialized by calling :cpp:func:`k_msgq_init()`.

The following code defines and initializes an empty message queue
that is capable of holding 10 items.
that is capable of holding 10 items, each of which is 12 bytes long.

.. code-block:: c
struct data_item_type {
...
uint32_t field1;
uint32_t field2;
uint32_t field3;
};
char __aligned(4) my_msgq_buffer[10 * sizeof(data_item_type)];
Expand Down
20 changes: 13 additions & 7 deletions doc/kernel_v2/memory/pools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ by its memory address.
A memory pool has the following key properties:

* A **minimum block size**, measured in bytes.
This must be at least 4 bytes long.
It must be at least 4X bytes long, where X is greater than 0.

* A **maximum block size**, measured in bytes.
This should be a power of 4 times larger than the minimum block size.
That is, "maximum block size" must equal "minimum block size" times 4^n,
where n is greater than or equal to zero.
That is, "maximum block size" must equal "minimum block size" times 4^Y,
where Y is greater than or equal to zero.

* The **number of maximum-size blocks** initially available.
This must be greater than zero.
Expand All @@ -40,6 +40,11 @@ A memory pool has the following key properties:
This must be at least "maximum block size" times
"number of maximum-size blocks" bytes long.

The memory pool's buffer must be aligned to an N-byte boundary, where
N is a power of 2 larger than 2 (i.e. 4, 8, 16, ...). To ensure that
all memory blocks in the buffer are similarly aligned to this boundary,
the minimum block size must also be a multiple of N.

A thread that needs to use a memory block simply allocates it from a memory
pool. Following a successful allocation, the :c:data:`data` field
of the block descriptor supplied by the thread indicates the starting address
Expand Down Expand Up @@ -129,7 +134,7 @@ as well as its buffer.

.. code-block:: c
K_MEM_POOL_DEFINE(my_map, 64, 4096, 3, 4);
K_MEM_POOL_DEFINE(my_pool, 64, 4096, 3, 4);
Allocating a Memory Block
=========================
Expand Down Expand Up @@ -197,9 +202,10 @@ Configuration Options

Related configuration options:

* CONFIG_MEM_POOL_AD_BEFORE_SEARCH_FOR_BIGGER_BLOCK
* CONFIG_MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGER_BLOCK
* CONFIG_MEM_POOL_AD_NONE
* :option:`CONFIG_MEM_POOL_AD_BEFORE_SEARCH_FOR_BIGGERBLOCK`
* :option:`CONFIG_MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGERBLOCK`
* :option:`CONFIG_MEM_POOL_AD_NONE`


APIs
****
Expand Down
14 changes: 11 additions & 3 deletions doc/kernel_v2/memory/slabs.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _memory_slabs_v2:

Memory slabs
Memory Slabs
############

A :dfn:`memory slab` is a kernel object that allows memory blocks
Expand All @@ -22,14 +22,22 @@ by its memory address.
A memory slab has the following key properties:

* The **block size** of each block, measured in bytes.
It must be at least 4 bytes long.
It must be at least 4N bytes long, where N is greater than 0.

* The **number of blocks** available for allocation.
It must be greater than zero.

* A **buffer** that provides the memory for the memory slab's blocks.
It must be at least "block size" times "number of blocks" bytes long.

The memory slab's buffer must be aligned to an N-byte boundary, where
N is a power of 2 larger than 2 (i.e. 4, 8, 16, ...). To ensure that
all memory blocks in the buffer are similarly aligned to this boundary,
the block size must also be a multiple of N.

A memory slab must be initialized before it can be used. This marks all of
its blocks as unused.

A thread that needs to use a memory block simply allocates it from a memory
slab. When the thread finishes with a memory block,
it must release the block back to the memory slab so the block can be reused.
Expand Down Expand Up @@ -63,7 +71,7 @@ A memory slab is defined using a variable of type :c:type:`struct k_mem_slab`.
It must then be initialized by calling :cpp:func:`k_mem_slab_init()`.

The following code defines and initializes a memory slab that has 6 blocks
of 400 bytes each and is aligned to a 4-byte boundary..
that are 400 bytes long, each of which is aligned to a 4-byte boundary..

.. code-block:: c
Expand Down
9 changes: 9 additions & 0 deletions doc/kernel_v2/other/atomic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ on a set of flag bits in a bit array longer than 32 bits.
other techniques to implement critical sections such as using a mutex
or locking interrupts.

Configuration Options
*********************

Related configuration options:

* :option:`CONFIG_ATOMIC_OPERATIONS_BUILTIN`
* :option:`CONFIG_ATOMIC_OPERATIONS_CUSTOM`
* :option:`CONFIG_ATOMIC_OPERATIONS_C`

APIs
****

Expand Down
2 changes: 1 addition & 1 deletion doc/kernel_v2/threads/lifecycle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ The following code spawns a thread that starts immediately.
extern void my_entry_point(void *, void *, void *);
char __noinit __stack my_stack_area[MY_THREAD_SIZE];
char __noinit __stack my_stack_area[MY_STACK_SIZE];
k_tid_t my_tid = k_thread_spawn(my_stack_area, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
Expand Down
1 change: 1 addition & 0 deletions doc/kernel_v2/threads/scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ Related configuration options:

* :option:`CONFIG_NUM_COOP_PRIORITIES`
* :option:`CONFIG_NUM_PREEMPT_PRIORITIES`
* :option:`CONFIG_TIMESLICING`
* :option:`CONFIG_TIMESLICE_SIZE`
* :option:`CONFIG_TIMESLICE_PRIORITY`

Expand Down
1 change: 1 addition & 0 deletions doc/kernel_v2/threads/system_threads.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Related configuration options:

* :option:`CONFIG_MAIN_THREAD_PRIORITY`
* :option:`CONFIG_MAIN_STACK_SIZE`
* :option:`CONFIG_IDLE_STACK_SIZE`

APIs
****
Expand Down
31 changes: 22 additions & 9 deletions include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -1561,8 +1561,9 @@ struct k_msgq {
*
* The message queue's ring buffer contains space for @a q_max_msgs messages,
* each of which is @a q_msg_size bytes long. The buffer is aligned to a
* @a q_align -byte boundary. To ensure that each message is aligned to a
* @a q_align -byte boundary, @a q_msg_size must be a multiple of @a q_align.
* @a q_align -byte boundary, which must be a power of 2. To ensure that each
* message is similarly aligned to this boundary, @a q_msg_size must also be
* a multiple of @a q_align.
*
* The message queue can be accessed outside the module where it is defined
* using:
Expand All @@ -1572,7 +1573,7 @@ struct k_msgq {
* @param q_name Name of the message queue.
* @param q_msg_size Message size (in bytes).
* @param q_max_msgs Maximum number of messages that can be queued.
* @param q_align Alignment of the message queue's ring buffer (power of 2).
* @param q_align Alignment of the message queue's ring buffer.
*/
#define K_MSGQ_DEFINE(q_name, q_msg_size, q_max_msgs, q_align) \
static char __noinit __aligned(q_align) \
Expand All @@ -1587,6 +1588,12 @@ struct k_msgq {
*
* This routine initializes a message queue object, prior to its first use.
*
* The message queue's ring buffer must contain space for @a max_msgs messages,
* each of which is @a msg_size bytes long. The buffer must be aligned to an
* N-byte boundary, where N is a power of 2 (i.e. 1, 2, 4, ...). To ensure
* that each message is similarly aligned to this boundary, @a q_msg_size
* must also be a multiple of N.
*
* @param q Address of the message queue.
* @param buffer Pointer to ring buffer that holds queued messages.
* @param msg_size Message size (in bytes).
Expand Down Expand Up @@ -2022,15 +2029,15 @@ struct k_mem_slab {
}

/**
* @brief Statically define and initialize a memory slab allocator.
* @brief Statically define and initialize a memory slab.
*
* The slab allocator's buffer contains @a slab_num_blocks memory blocks
* The memory slab's buffer contains @a slab_num_blocks memory blocks
* that are @a slab_block_size bytes long. The buffer is aligned to a
* @a slab_align -byte boundary. To ensure that each memory block is aligned
* to a @a slab_align -byte boundary, @a slab_block_size must be a multiple of
* @a slab_align -byte boundary. To ensure that each memory block is similarly
* aligned to this boundary, @a slab_block_size must also be a multiple of
* @a slab_align.
*
* The slab allocator can be accessed outside the module where it is defined
* The memory slab can be accessed outside the module where it is defined
* using:
*
* extern struct k_mem_slab @a name;
Expand All @@ -2053,6 +2060,12 @@ struct k_mem_slab {
*
* Initializes a memory slab, prior to its first use.
*
* The memory slab's buffer contains @a slab_num_blocks memory blocks
* that are @a slab_block_size bytes long. The buffer must be aligned to an
* N-byte boundary, where N is a power of 2 larger than 2 (i.e. 4, 8, 16, ...).
* To ensure that each memory block is similarly aligned to this boundary,
* @a slab_block_size must also be a multiple of N.
*
* @param slab Address of the memory slab.
* @param buffer Pointer to buffer used for the memory blocks.
* @param block_size Size of each memory block (in bytes).
Expand Down Expand Up @@ -2338,7 +2351,7 @@ static void __attribute__ ((used)) __k_mem_pool_quad_block_size_define(void)
* long. The memory pool allows blocks to be repeatedly partitioned into
* quarters, down to blocks of @a min_size bytes long. The buffer is aligned
* to a @a align -byte boundary. To ensure that the minimum sized blocks are
* aligned to @a align -byte boundary, @a min_size must be a multiple of
* similarly aligned to this boundary, @a min_size must also be a multiple of
* @a align.
*
* If the pool is to be accessed outside the module where it is defined, it
Expand Down

0 comments on commit da82722

Please sign in to comment.