btstackの実装 メモリ管理を読む

btstackのメモリ管理部分の実装を読みました。

btstackは組込み向けのbluetoothプロトコルスタックです。

btstackは組込み向けのportではメモリプールを使う実装になっています。

# ソース
* https://github.com/bluekitchen/btstack
 * https://github.com/bluekitchen/btstack/blob/master/src/btstack_memory.c
 * https://github.com/bluekitchen/btstack/blob/master/src/btstack_memory.h
 * https://github.com/bluekitchen/btstack/blob/master/src/btstack_memory.c
 * https://github.com/bluekitchen/btstack/blob/master/src/btstack_memory.h 

# メモリの初期化 (メモリプールの場合)
* btstack_memory.c の btstack_memory_init()で初期化する。
* btstack_memory_pool_create()で種類毎のメモリプールを作る。
 * hci_connection
 * l2cap_service
 * rfcomm_multiplexer
 * rfcomm_service
 * rfcomm_channel
 * btstack_link_key_db_memory_entry
 * bnep_service
 * bnep_channel
 * hfp_connection
 * service_record_item
 * gatt_client
 * whitelist_entry
 * sm_lookup_entry 

```c:btstack_memory.c 
void btstack_memory_init(void){
#if MAX_NR_HCI_CONNECTIONS > 0
    btstack_memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NR_HCI_CONNECTIONS, sizeof(hci_connection_t));
...
```

* storageにブロックサイズblock_sizeバイトのメモリブロックをcount個作成する。メモリプール管理情報はpoolにある。

```c:btstack_memory_pool.c
void btstack_memory_pool_create(btstack_memory_pool_t *pool, void * storage, int count, int block_size){
    node_t *free_blocks = (node_t*) pool;
    char   *mem_ptr = (char *) storage;
    int i;
    
    // create singly linked list of all available blocks
    free_blocks->next = NULL;
    for (i = 0 ; i < count ; i++){
        btstack_memory_pool_free(pool, mem_ptr);
        mem_ptr += block_size;
    }
}
```

* storageは静的に確保する

```c:btstack_memory.c 
static hci_connection_t hci_connection_storage[MAX_NR_HCI_CONNECTIONS];
```

# メモリの確保と解放
コンパイルオプションで3種類ある
* メモリプール 個数1以上
* メモリプール 個数0
* malloc()/free()を利用

## メモリの確保と解放 メモリプール 個数1以上
* MAX_NR_HCI_CONNECTIONS > 0 の場合

```c:btstack_memory.c 
#ifdef MAX_NR_HCI_CONNECTIONS
#if MAX_NR_HCI_CONNECTIONS > 0
static hci_connection_t hci_connection_storage[MAX_NR_HCI_CONNECTIONS];
static btstack_memory_pool_t hci_connection_pool;
hci_connection_t * btstack_memory_hci_connection_get(void){
    return (hci_connection_t *) btstack_memory_pool_get(&hci_connection_pool);
}
void btstack_memory_hci_connection_free(hci_connection_t *hci_connection){
    btstack_memory_pool_free(&hci_connection_pool, hci_connection);
}
#else
#endif
#endif
```
### btstack_memory_pool_get
* 空いているメモリブロックを返す。

```c:btstack_memory_pool.c
void * btstack_memory_pool_get(btstack_memory_pool_t *pool){
    node_t *free_blocks = (node_t*) pool;
    
    if (!free_blocks->next) return NULL;
    
    // remove first
    node_t *node      = free_blocks->next;
    free_blocks->next = node->next;
    
    return (void*) node;
}
```
### btstack_memory_pool_free
* 二重解放をチェックする
* 空きメモリブロックリストに追加する

```c:btstack_memory_pool.c
void btstack_memory_pool_free(btstack_memory_pool_t *pool, void * block){
    node_t *free_blocks = (node_t*) pool;
    node_t *node        = (node_t*) block;

    // raise error and abort if node already in list
    node_t * it;
    for (it = free_blocks->next; it ; it = it->next){
        if (it == node) {
            log_error("btstack_memory_pool_free: block %p freed twice for pool %p", block, pool);
            return;
        }
    }

    // add block as node to list
    node->next          = free_blocks->next;
    free_blocks->next   = node;
}
```
## メモリの確保と解放 メモリプール 個数0
* MAX_NR_HCI_CONNECTIONS == 0 の場合。　どう使うのか不明。

```c:btstack_memory.c 
#ifdef MAX_NR_HCI_CONNECTIONS
#if MAX_NR_HCI_CONNECTIONS > 0
#else
hci_connection_t * btstack_memory_hci_connection_get(void){
    return NULL;
}
void btstack_memory_hci_connection_free(hci_connection_t *hci_connection){
    // silence compiler warning about unused parameter in a portable way
    (void) hci_connection;
};
#endif
#endif
```


## メモリの確保と解放 malloc()/free()を利用
* 単純に malloc()とfree() する。

```c:btstack_memory.c 
#elif defined(HAVE_MALLOC)
hci_connection_t * btstack_memory_hci_connection_get(void){
    return (hci_connection_t*) malloc(sizeof(hci_connection_t));
}
void btstack_memory_hci_connection_free(hci_connection_t *hci_connection){
    free(hci_connection);
}
#endif
```

# 各portのHCIのメモリ確保の種類
##  メモリプール (MAX_NR_HCI_CONNECTIONS 1)
* arduino
* ez430-rf2560
* msp430f5229lp-cc2564b
* msp-exp430f5438-cc2564b
* nrf5x
* pic32-harmony
* wiced
* stm32-f103rb-nucleo

## malloc (HAVE_MALLOC)
* libusb
* posix-h4
* posix-h5
* ios