net: buf: Remove the need for net_buf_pool_init()

In order to keep the initialization process light-weight, remove
net_buf_pool_init() and instead perform the initialization of the pool
and buffers in a "lazy" manner. This means storing more information
in the pool, and removing any 'const' members from net_buf. Since
there are no more const members in net_buf the buffer array can be
declared with __noinit, which further reduces initialization overhead.

Change-Id: Ia126af101c2727c130651b697dcba99d159a1c76
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2016-12-14 08:33:50 +02:00
parent 45bc46d42e
commit 71c7c01819
31 changed files with 142 additions and 173 deletions

View file

@ -14,18 +14,18 @@ Network buffers are created by first defining a pool of them:
NET_BUF_POOL_DEFINE(pool_name, buf_count, buf_size, user_data_size, NULL);
Before operating on the pool it also needs to be initialized at runtime:
The pool is a static variable, so if it's needed to be exported to
another module a separate pointer is needed.
Once the pool has been defined, buffers can be allocated from it with:
.. code-block:: c
net_buf_pool_init(&pool_name);
buf = net_buf_alloc(&pool_name, timeout);
Once the pool has been initialized the available buffers are managed
with the help of a nano_fifo object and can be acquired with:
.. code-block:: c
buf = net_buf_alloc(&pool_name);
There is no explicit initialization function for the pool or its
buffers, rather this is done implicitly as :c:func:`net_buf_alloc` gets
called.
If there is a need to reserve space in the buffer for protocol headers
to be prependend later, it's possible to reserve this headroom with:

View file

@ -701,9 +701,6 @@ static void h5_init(void)
k_thread_spawn(tx_stack, sizeof(tx_stack), (k_thread_entry_t)tx_thread,
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
/* RX thread */
net_buf_pool_init(&h5_pool);
k_fifo_init(&h5.rx_queue);
k_thread_spawn(rx_stack, sizeof(rx_stack), (k_thread_entry_t)rx_thread,
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);

View file

@ -1584,7 +1584,6 @@ void bt_gatt_init(void)
#if CONFIG_BLUETOOTH_ATT_PREPARE_COUNT > 0
k_fifo_init(&queue);
net_buf_pool_init(&prep_pool);
#endif
}

View file

@ -250,9 +250,6 @@ static int _bt_nble_init(struct device *unused)
return -EINVAL;
}
net_buf_pool_init(&rx_pool);
net_buf_pool_init(&tx_pool);
return 0;
}

View file

@ -76,7 +76,7 @@ struct net_buf_simple {
uint16_t len;
/** Amount of data that this buffer can store. */
const uint16_t size;
uint16_t size;
/** Start of the data storage. Not to be accessed directly
* (the data pointer should be used instead).
@ -400,7 +400,7 @@ struct net_buf {
sys_snode_t sent_list;
/** Size of the user data associated with this buffer. */
const uint16_t user_data_size;
uint16_t user_data_size;
/** Reference count. */
uint8_t ref;
@ -424,7 +424,7 @@ struct net_buf {
uint16_t len;
/** Amount of data that this buffer can store. */
const uint16_t size;
uint16_t size;
};
struct net_buf_simple b;
@ -443,6 +443,15 @@ struct net_buf_pool {
/** Number of buffers in pool */
const uint16_t buf_count;
/** Number of uninitialized buffers */
uint16_t uninit_count;
/** Data size of each buffer in the pool */
const uint16_t buf_size;
/** Size of the user data associated with each buffer. */
const uint16_t user_data_size;
/** Optional destroy callback when buffer is freed. */
void (*const destroy)(struct net_buf *buf);
@ -450,10 +459,15 @@ struct net_buf_pool {
struct net_buf * const __bufs;
};
#define NET_BUF_POOL_INITIALIZER(_bufs, _count, _destroy) \
#define NET_BUF_POOL_INITIALIZER(_pool, _bufs, _count, _size, _ud_size, \
_destroy) \
{ \
.free = K_FIFO_INITIALIZER(_pool.free), \
.__bufs = (struct net_buf *)_bufs, \
.buf_count = _count, \
.uninit_count = _count, \
.buf_size = _size, \
.user_data_size = _ud_size, \
.destroy = _destroy, \
}
@ -461,12 +475,11 @@ struct net_buf_pool {
* @brief Define a new pool for buffers
*
* Defines a net_buf_pool struct and the necessary memory storage (array of
* structs) for the needed amount of buffers. After this the
* net_buf_pool_init(&pool_name) API still needs to be used (at runtime),
* after which the buffers can be accessed from the pool. The pool is defined
* as a static variable, so if it needs to be exported outside the current
* module this needs to happen with the help of a separate pointer rather
* than an extern declaration.
* structs) for the needed amount of buffers. After this,the buffers can be
* accessed from the pool through net_buf_alloc. The pool is defined as a
* static variable, so if it needs to be exported outside the current module
* this needs to happen with the help of a separate pointer rather than an
* extern declaration.
*
* If provided with a custom destroy callback this callback is
* responsible for eventually calling net_buf_destroy() to complete the
@ -483,26 +496,10 @@ struct net_buf_pool {
struct net_buf buf; \
uint8_t data[_size] __net_buf_align; \
uint8_t ud[ROUND_UP(_ud_size, 4)] __net_buf_align; \
} _net_buf_pool_##_name[_count] = { \
[0 ... (_count - 1)] = { \
.buf = { \
.size = _size, \
.user_data_size = _ud_size, \
}, \
} \
}; \
} _net_buf_pool_##_name[_count] __noinit; \
static struct net_buf_pool _name = \
NET_BUF_POOL_INITIALIZER(_net_buf_pool_##_name, _count, \
_destroy)
/**
* @brief Initialize a buffer pool.
*
* Initializes a buffer pool defined using NET_BUF_POOL_DEFINE().
*
* @param pool Buffer pool to initialize.
*/
void net_buf_pool_init(struct net_buf_pool *pool);
NET_BUF_POOL_INITIALIZER(_name, _net_buf_pool_##_name, \
_count, _size, _ud_size, _destroy)
/**
* @brief Allocate a new buffer from a pool.

View file

@ -63,9 +63,6 @@ NET_BUF_POOL_DEFINE(dns_qname_pool, DNS_RESOLVER_BUF_CTR, DNS_MAX_NAME_LEN,
int dns_init(void)
{
net_buf_pool_init(&dns_msg_pool);
net_buf_pool_init(&dns_qname_pool);
return 0;
}

View file

@ -38,8 +38,6 @@ int mqtt_init(struct mqtt_ctx *ctx, enum mqtt_app app_type)
/* So far, only clean session = 1 is supported */
ctx->clean_session = 1;
net_buf_pool_init(&mqtt_msg_pool);
return 0;
}

View file

@ -358,9 +358,6 @@ void main(void)
SYS_LOG_DBG("Start");
/* Initialize the buffer pools */
net_buf_pool_init(&cmd_tx_pool);
net_buf_pool_init(&acl_tx_pool);
/* Initialize the FIFOs */
k_fifo_init(&tx_queue);
k_fifo_init(&rx_queue);

View file

@ -691,9 +691,6 @@ void main(void)
{
SYS_LOG_DBG("Start");
/* Initialize the buffer pools */
net_buf_pool_init(&tx_pool);
net_buf_pool_init(&acl_tx_pool);
k_fifo_init(&rx_queue);
bt_enable_raw(&rx_queue);

View file

@ -16,6 +16,15 @@
#include <ztest.h>
unsigned int irq_lock(void)
{
return 0;
}
void irq_unlock(unsigned int key)
{
}
#include <net/buf.c>
void k_fifo_init(struct k_fifo *fifo) {}
@ -28,35 +37,36 @@ int k_is_in_isr(void)
void *k_fifo_get(struct k_fifo *fifo, int32_t timeout)
{
return ztest_get_return_value_ptr();
return NULL;
}
void k_fifo_put(struct k_fifo *fifo, void *data)
{
ztest_check_expected_value(data);
}
#define BUF_COUNT 1
#define BUF_SIZE 74
void k_lifo_init(struct k_lifo *lifo) {}
NET_BUF_POOL_DEFINE(bufs_pool, BUF_COUNT, BUF_SIZE, sizeof(int), NULL);
static void init_pool(void)
void *k_lifo_get(struct k_lifo *lifo, int32_t timeout)
{
ztest_expect_value(k_fifo_put, data, bufs_pool.__bufs);
net_buf_pool_init(&bufs_pool);
return NULL;
}
void k_lifo_put(struct k_lifo *lifo, void *data)
{
}
#define TEST_BUF_COUNT 1
#define TEST_BUF_SIZE 74
NET_BUF_POOL_DEFINE(bufs_pool, TEST_BUF_COUNT, TEST_BUF_SIZE,
sizeof(int), NULL);
static void test_get_single_buffer(void)
{
struct net_buf *buf;
init_pool();
ztest_returns_value(k_fifo_get, bufs_pool.__bufs);
buf = net_buf_alloc(&bufs_pool, K_NO_WAIT);
assert_equal_ptr(buf, bufs_pool.__bufs, "Returned buffer not from pool");
assert_equal(buf->ref, 1, "Invalid refcount");
assert_equal(buf->len, 0, "Invalid length");
assert_equal(buf->flags, 0, "Invalid flags");

View file

@ -1970,12 +1970,6 @@ void bt_att_init(void)
.accept = bt_att_accept,
};
net_buf_pool_init(&req_pool);
net_buf_pool_init(&rsp_pool);
#if CONFIG_BLUETOOTH_ATT_PREPARE_COUNT > 0
net_buf_pool_init(&prep_pool);
#endif
bt_l2cap_le_fixed_chan_register(&chan);
}

View file

@ -41,9 +41,11 @@
#define CONFIG_BLUETOOTH_AVDTP_CONN CONFIG_BLUETOOTH_MAX_CONN
/* Pool for outgoing BR/EDR signaling packets, min MTU is 48 */
/*
NET_BUF_POOL_DEFINE(avdtp_sig_pool, CONFIG_BLUETOOTH_AVDTP_CONN,
BT_AVDTP_BUF_SIZE(BT_AVDTP_MIN_MTU),
BT_BUF_USER_DATA_MIN, NULL);
*/
static struct bt_avdtp bt_avdtp_pool[CONFIG_BLUETOOTH_AVDTP_CONN];
@ -195,9 +197,6 @@ int bt_avdtp_init(void)
BT_DBG("");
/* Memory Initialization */
net_buf_pool_init(&avdtp_sig_pool);
/* Register AVDTP PSM with L2CAP */
err = bt_l2cap_br_server_register(&avdtp_l2cap);
if (err < 0) {

View file

@ -1739,9 +1739,6 @@ int bt_conn_init(void)
{
int err;
net_buf_pool_init(&frag_pool);
net_buf_pool_init(&dummy_pool);
bt_att_init();
err = bt_smp_init();

View file

@ -3662,16 +3662,6 @@ int bt_enable(bt_ready_cb_t cb)
return -EALREADY;
}
/* Initialize the buffer pools */
net_buf_pool_init(&hci_cmd_pool);
#if defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
net_buf_pool_init(&hci_evt_pool);
net_buf_pool_init(&hci_evt_prio_pool);
#if defined(CONFIG_BLUETOOTH_CONN)
net_buf_pool_init(&acl_in_pool);
#endif /* CONFIG_BLUETOOTH_CONN */
#endif /* CONFIG_BLUETOOTH_HOST_BUFFERS */
/* Give cmd_sem allowing to send first HCI_Reset cmd, the only
* exception is if the controller requests to wait for an
* initial Command Complete for NOP.

View file

@ -116,9 +116,6 @@ int bt_enable_raw(struct k_fifo *rx_queue)
BT_DBG("");
net_buf_pool_init(&hci_evt_pool);
net_buf_pool_init(&acl_in_pool);
raw_rx = rx_queue;
if (!bt_dev.drv) {

View file

@ -218,8 +218,6 @@ static void hfp_hf_init(void)
.accept = bt_hfp_hf_accept,
};
net_buf_pool_init(&hf_pool);
bt_rfcomm_server_register(&chan);
}

View file

@ -1410,11 +1410,6 @@ void bt_l2cap_init(void)
.accept = l2cap_accept,
};
net_buf_pool_init(&le_sig_pool);
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
net_buf_pool_init(&le_data_pool);
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
bt_l2cap_le_fixed_chan_register(&chan);
#if defined(CONFIG_BLUETOOTH_BREDR)

View file

@ -1658,7 +1658,6 @@ void bt_l2cap_br_init(void)
.accept = l2cap_br_accept,
};
net_buf_pool_init(&br_sig_pool);
bt_l2cap_br_fixed_chan_register(&chan_br);
#if defined(CONFIG_BLUETOOTH_RFCOMM)
bt_rfcomm_init();

View file

@ -1317,7 +1317,5 @@ void bt_rfcomm_init(void)
.sec_level = BT_SECURITY_LOW,
};
net_buf_pool_init(&rfcomm_session_pool);
net_buf_pool_init(&dummy_pool);
bt_l2cap_br_server_register(&server);
}

View file

@ -277,8 +277,6 @@ void bt_sdp_init(void)
};
int res;
net_buf_pool_init(&sdp_pool);
res = bt_l2cap_br_server_register(&server);
if (res) {
BT_ERR("L2CAP server registration failed with error %d", res);

View file

@ -4420,8 +4420,6 @@ int bt_smp_init(void)
}
#endif /* CONFIG_BLUETOOTH_SMP_SC_ONLY */
net_buf_pool_init(&smp_pool);
bt_l2cap_le_fixed_chan_register(&chan);
#if defined(CONFIG_BLUETOOTH_BREDR)
/* Register BR/EDR channel only if BR/EDR SC is supported */

View file

@ -109,8 +109,6 @@ int bt_smp_init(void)
.accept = bt_smp_accept,
};
net_buf_pool_init(&smp_pool);
bt_l2cap_le_fixed_chan_register(&chan);
return 0;

View file

@ -46,6 +46,29 @@
#define NET_BUF_ASSERT(cond)
#endif /* CONFIG_NET_BUF_DEBUG */
/* Helpers to access the storage array, since we don't have access to its
* type at this point anymore.
*/
#define BUF_SIZE(pool) (sizeof(struct net_buf) + \
ROUND_UP(pool->buf_size, 4) + \
ROUND_UP(pool->user_data_size, 4))
#define UNINIT_BUF(pool, n) (struct net_buf *)(((uint8_t *)(pool->__bufs)) + \
((n) * BUF_SIZE(pool)))
static inline struct net_buf *pool_get_uninit(struct net_buf_pool *pool,
uint16_t uninit_count)
{
struct net_buf *buf;
buf = UNINIT_BUF(pool, pool->buf_count - uninit_count);
buf->pool = pool;
buf->size = pool->buf_size;
buf->user_data_size = pool->user_data_size;
return buf;
}
#if defined(CONFIG_NET_BUF_DEBUG)
struct net_buf *net_buf_alloc_debug(struct net_buf_pool *pool, int32_t timeout,
const char *func, int line)
@ -54,14 +77,47 @@ struct net_buf *net_buf_alloc(struct net_buf_pool *pool, int32_t timeout)
#endif
{
struct net_buf *buf;
unsigned int key;
NET_BUF_ASSERT(pool);
NET_BUF_DBG("pool %p timeout %d", pool, timeout);
/* We need to lock interrupts temporarily to prevent race conditions
* when accessing pool->uninit_count.
*/
key = irq_lock();
/* If there are uninitialized buffers we're guaranteed to succeed
* with the allocation one way or another.
*/
if (pool->uninit_count) {
uint16_t uninit_count;
/* If this is not the first access to the pool, we can
* be opportunistic and try to fetch a previously used
* buffer from the FIFO with K_NO_WAIT.
*/
if (pool->uninit_count < pool->buf_count) {
buf = k_fifo_get(&pool->free, K_NO_WAIT);
if (buf) {
irq_unlock(key);
goto success;
}
}
uninit_count = pool->uninit_count--;
irq_unlock(key);
buf = pool_get_uninit(pool, uninit_count);
goto success;
}
irq_unlock(key);
#if defined(CONFIG_NET_BUF_DEBUG)
if (timeout == K_FOREVER) {
buf = net_buf_alloc(pool, K_NO_WAIT);
buf = k_fifo_get(&pool->free, K_NO_WAIT);
if (!buf) {
NET_BUF_WARN("%s():%d: Pool %p low on buffers.",
func, line, pool);
@ -78,6 +134,7 @@ struct net_buf *net_buf_alloc(struct net_buf_pool *pool, int32_t timeout)
return NULL;
}
success:
NET_BUF_DBG("allocated buf %p");
buf->ref = 1;
@ -123,28 +180,6 @@ struct net_buf *net_buf_get(struct k_fifo *fifo, int32_t timeout)
return buf;
}
/* Helper to iterate the storage array, since we don't have access to its type
* at this point anymore.
*/
#define NEXT_BUF(buf) ((struct net_buf *)(((uint8_t *)buf) + sizeof(*buf) + \
ROUND_UP(buf->size, 4) + \
ROUND_UP(buf->user_data_size, 4)))
void net_buf_pool_init(struct net_buf_pool *pool)
{
struct net_buf *buf;
uint16_t i;
k_fifo_init(&pool->free);
buf = pool->__bufs;
for (i = 0; i < pool->buf_count; i++) {
buf->pool = pool;
k_fifo_put(&pool->free, buf);
buf = NEXT_BUF(buf);
}
}
void net_buf_reserve(struct net_buf *buf, size_t reserve)
{
NET_BUF_ASSERT(buf);

View file

@ -1390,8 +1390,4 @@ void net_nbuf_init(void)
NBUF_RX_COUNT, sizeof(rx_buffers),
NBUF_TX_COUNT, sizeof(tx_buffers),
NBUF_DATA_COUNT, sizeof(data_buffers));
net_buf_pool_init(&rx_buffers);
net_buf_pool_init(&tx_buffers);
net_buf_pool_init(&data_buffers);
}

View file

@ -57,7 +57,9 @@ static bt_addr_le_t id_addr;
/* Connection context for BR/EDR legacy pairing in sec mode 3 */
static struct bt_conn *pairing_conn;
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
NET_BUF_POOL_DEFINE(data_pool, 1, DATA_MTU, BT_BUF_USER_DATA_MIN, NULL);
#endif
#if defined(CONFIG_BLUETOOTH_BREDR)
NET_BUF_POOL_DEFINE(data_bredr_pool, 1, DATA_BREDR_MTU, BT_BUF_USER_DATA_MIN,
@ -2306,11 +2308,6 @@ void main(void)
{
bt_conn_cb_register(&conn_callbacks);
net_buf_pool_init(&data_pool);
#if defined(CONFIG_BLUETOOTH_BREDR)
net_buf_pool_init(&data_bredr_pool);
#endif /* CONFIG_BLUETOOTH_BREDR */
printk("Type \"help\" for supported commands.\n");
printk("Before any Bluetooth commands you must run \"init\".\n");

View file

@ -1786,8 +1786,6 @@ void tester_handle_gatt(uint8_t opcode, uint8_t index, uint8_t *data,
uint8_t tester_init_gatt(void)
{
net_buf_pool_init(&server_pool);
server_buf = net_buf_alloc(&server_pool, K_NO_WAIT);
if (!server_buf) {
return BTP_STATUS_FAILED;

View file

@ -358,7 +358,5 @@ void tester_handle_l2cap(uint8_t opcode, uint8_t index, uint8_t *data,
uint8_t tester_init_l2cap(void)
{
net_buf_pool_init(&data_pool);
return BTP_STATUS_SUCCESS;
}

View file

@ -217,9 +217,6 @@ static void net_buf_test_4(void)
struct net_buf *buf, *frag;
int i, removed;
net_buf_pool_init(&no_data_pool);
net_buf_pool_init(&frags_pool);
/* Create a buf that does not have any data to store, it just
* contains link to fragments.
*/
@ -331,8 +328,6 @@ static void net_buf_test_big_buf(void)
struct udp_hdr *udp;
int i, len;
net_buf_pool_init(&big_frags_pool);
frag_destroy_called = 0;
buf = net_buf_alloc(&no_data_pool, K_FOREVER);
@ -419,8 +414,6 @@ static void net_buf_test_multi_frags(void)
void test_main(void)
{
net_buf_pool_init(&bufs_pool);
ztest_test_suite(net_buf_test,
ztest_unit_test(net_buf_test_1),
ztest_unit_test(net_buf_test_2),

View file

@ -75,9 +75,6 @@ static bool run_tests(void)
struct net_buf *buf, *frag;
int ret;
net_buf_pool_init(&bufs_pool);
net_buf_pool_init(&data_pool);
net_icmpv6_register_handler(&test_handler1);
net_icmpv6_register_handler(&test_handler2);

View file

@ -1058,10 +1058,6 @@ int main(int argc, char *argv[])
TC_START("Test Zoap CoAP PDU parsing and building");
net_buf_pool_init(&zoap_nbuf_pool);
net_buf_pool_init(&zoap_data_pool);
net_buf_pool_init(&zoap_limited_data_pool);
for (count = 0, pass = 0; count < ARRAY_SIZE(tests); count++) {
if (tests[count].func() == TC_PASS) {
pass++;

View file

@ -16,6 +16,15 @@
#include <ztest.h>
unsigned int irq_lock(void)
{
return 0;
}
void irq_unlock(unsigned int key)
{
}
#include <net/buf.c>
void k_fifo_init(struct k_fifo *fifo) {}
@ -28,36 +37,36 @@ int k_is_in_isr(void)
void *k_fifo_get(struct k_fifo *fifo, int32_t timeout)
{
return ztest_get_return_value_ptr();
return NULL;
}
void k_fifo_put(struct k_fifo *fifo, void *data)
{
ztest_check_expected_value(data);
}
#define BUF_COUNT 1
#define BUF_SIZE 74
void k_lifo_init(struct k_lifo *lifo) {}
NET_BUF_POOL_DEFINE(bufs_pool, BUF_COUNT, BUF_SIZE, sizeof(int), NULL);
static void init_pool(void)
void *k_lifo_get(struct k_lifo *lifo, int32_t timeout)
{
ztest_expect_value(k_fifo_put, data, bufs_pool.__bufs);
net_buf_pool_init(&bufs_pool);
return NULL;
}
void k_lifo_put(struct k_lifo *lifo, void *data)
{
}
#define TEST_BUF_COUNT 1
#define TEST_BUF_SIZE 74
NET_BUF_POOL_DEFINE(bufs_pool, TEST_BUF_COUNT, TEST_BUF_SIZE,
sizeof(int), NULL);
static void test_get_single_buffer(void)
{
struct net_buf *buf;
init_pool();
ztest_returns_value(k_fifo_get, bufs_pool.__bufs);
buf = net_buf_alloc(&bufs_pool, K_NO_WAIT);
assert_equal_ptr(buf, bufs_pool.__bufs,
"Returned buffer not from pool");
assert_equal(buf->ref, 1, "Invalid refcount");
assert_equal(buf->len, 0, "Invalid length");
assert_equal(buf->flags, 0, "Invalid flags");