1#!/usr/bin/env python3 2import os 3import sys 4 5import os 6import sys 7 8copyright = """/* 9 * Copyright (C) 2014 BlueKitchen GmbH 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the copyright holders nor the names of 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 4. Any redistribution, use, or modification is done solely for 24 * personal benefit and not for any commercial purpose or for 25 * monetary gain. 26 * 27 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 31 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 34 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 37 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * Please inquire about commercial licensing options at 41 * [email protected] 42 * 43 */ 44""" 45 46hfile_header_begin = """ 47 48/* 49 * btstack_memory.h 50 * 51 * @brief BTstack memory management via configurable memory pools 52 * 53 */ 54 55#ifndef BTSTACK_MEMORY_H 56#define BTSTACK_MEMORY_H 57 58#if defined __cplusplus 59extern "C" { 60#endif 61 62#include "btstack_config.h" 63 64// Core 65#include "hci.h" 66#include "l2cap.h" 67 68// Classic 69#include "classic/avdtp_sink.h" 70#include "classic/avdtp_source.h" 71#include "classic/avrcp.h" 72#include "classic/bnep.h" 73#include "classic/btstack_link_key_db.h" 74#include "classic/btstack_link_key_db_memory.h" 75#include "classic/hfp.h" 76#include "classic/hid_host.h" 77#include "classic/rfcomm.h" 78#include "classic/sdp_server.h" 79 80// BLE 81#ifdef ENABLE_BLE 82#include "ble/gatt_client.h" 83#include "ble/sm.h" 84#endif 85 86#ifdef ENABLE_MESH 87#include "mesh/mesh_network.h" 88#include "mesh/mesh_keys.h" 89#include "mesh/mesh_virtual_addresses.h" 90#endif 91 92/* API_START */ 93 94/** 95 * @brief Initializes BTstack memory pools. 96 */ 97void btstack_memory_init(void); 98 99/** 100 * @brief Deinitialize BTstack memory pools 101 * @note if HAVE_MALLOC is defined, all previously allocated buffers are free'd 102 */ 103void btstack_memory_deinit(void); 104 105/* API_END */ 106""" 107 108hfile_header_end = """ 109#if defined __cplusplus 110} 111#endif 112 113#endif // BTSTACK_MEMORY_H 114""" 115 116cfile_header_begin = """ 117#define BTSTACK_FILE__ "btstack_memory.c" 118 119 120/* 121 * btstack_memory.c 122 * 123 * @brief BTstack memory management via configurable memory pools 124 * 125 * @note code generated by tool/btstack_memory_generator.py 126 * @note returnes buffers are initialized with 0 127 * 128 */ 129 130#include "btstack_memory.h" 131#include "btstack_memory_pool.h" 132#include "btstack_debug.h" 133 134#include <stdlib.h> 135 136#ifdef HAVE_MALLOC 137typedef struct btstack_memory_buffer { 138 struct btstack_memory_buffer * next; 139 struct btstack_memory_buffer * prev; 140} btstack_memory_buffer_t; 141 142typedef struct { 143 btstack_memory_buffer_t tracking; 144 void * pointer; 145} test_buffer_t; 146 147static btstack_memory_buffer_t * btstack_memory_malloc_buffers; 148static uint32_t btstack_memory_malloc_counter; 149 150static void btstack_memory_tracking_add(btstack_memory_buffer_t * buffer){ 151 btstack_assert(buffer != NULL); 152 if (btstack_memory_malloc_buffers != NULL) { 153 // let current first item prev point to new first item 154 btstack_memory_malloc_buffers->prev = buffer; 155 } 156 buffer->prev = NULL; 157 buffer->next = btstack_memory_malloc_buffers; 158 btstack_memory_malloc_buffers = buffer; 159 160 btstack_memory_malloc_counter++; 161} 162 163static void btstack_memory_tracking_remove(btstack_memory_buffer_t * buffer){ 164 btstack_assert(buffer != NULL); 165 if (buffer->prev == NULL){ 166 // first item 167 btstack_memory_malloc_buffers = buffer->next; 168 } else { 169 buffer->prev->next = buffer->next; 170 } 171 if (buffer->next != NULL){ 172 buffer->next->prev = buffer->prev; 173 } 174 175 btstack_memory_malloc_counter--; 176} 177#endif 178 179void btstack_memory_deinit(void){ 180#ifdef HAVE_MALLOC 181 while (btstack_memory_malloc_buffers != NULL){ 182 btstack_memory_buffer_t * buffer = btstack_memory_malloc_buffers; 183 btstack_memory_malloc_buffers = buffer->next; 184 free(buffer); 185 } 186 btstack_assert(btstack_memory_malloc_counter == 0); 187#endif 188} 189""" 190 191header_template = """STRUCT_NAME_t * btstack_memory_STRUCT_NAME_get(void); 192void btstack_memory_STRUCT_NAME_free(STRUCT_NAME_t *STRUCT_NAME);""" 193 194code_template = """ 195// MARK: STRUCT_TYPE 196#if !defined(HAVE_MALLOC) && !defined(POOL_COUNT) 197 #if defined(POOL_COUNT_OLD_NO) 198 #error "Deprecated POOL_COUNT_OLD_NO defined instead of POOL_COUNT. Please update your btstack_config.h to use POOL_COUNT." 199 #else 200 #define POOL_COUNT 0 201 #endif 202#endif 203 204#ifdef POOL_COUNT 205#if POOL_COUNT > 0 206static STRUCT_TYPE STRUCT_NAME_storage[POOL_COUNT]; 207static btstack_memory_pool_t STRUCT_NAME_pool; 208STRUCT_NAME_t * btstack_memory_STRUCT_NAME_get(void){ 209 void * buffer = btstack_memory_pool_get(&STRUCT_NAME_pool); 210 if (buffer){ 211 memset(buffer, 0, sizeof(STRUCT_TYPE)); 212 } 213 return (STRUCT_NAME_t *) buffer; 214} 215void btstack_memory_STRUCT_NAME_free(STRUCT_NAME_t *STRUCT_NAME){ 216 btstack_memory_pool_free(&STRUCT_NAME_pool, STRUCT_NAME); 217} 218#else 219STRUCT_NAME_t * btstack_memory_STRUCT_NAME_get(void){ 220 return NULL; 221} 222void btstack_memory_STRUCT_NAME_free(STRUCT_NAME_t *STRUCT_NAME){ 223 UNUSED(STRUCT_NAME); 224}; 225#endif 226#elif defined(HAVE_MALLOC) 227 228typedef struct { 229 btstack_memory_buffer_t tracking; 230 STRUCT_NAME_t data; 231} btstack_memory_STRUCT_NAME_t; 232 233STRUCT_NAME_t * btstack_memory_STRUCT_NAME_get(void){ 234 btstack_memory_STRUCT_NAME_t * buffer = (btstack_memory_STRUCT_NAME_t *) malloc(sizeof(btstack_memory_STRUCT_NAME_t)); 235 if (buffer){ 236 memset(buffer, 0, sizeof(btstack_memory_STRUCT_NAME_t)); 237 btstack_memory_tracking_add(&buffer->tracking); 238 return &buffer->data; 239 } else { 240 return NULL; 241 } 242} 243void btstack_memory_STRUCT_NAME_free(STRUCT_NAME_t *STRUCT_NAME){ 244 // reconstruct buffer start 245 btstack_memory_buffer_t * buffer = &((btstack_memory_buffer_t *) STRUCT_NAME)[-1]; 246 btstack_memory_tracking_remove(buffer); 247 free(buffer); 248} 249#endif 250""" 251init_header = ''' 252// init 253void btstack_memory_init(void){ 254#ifdef HAVE_MALLOC 255 // assert that there is no unexpected padding for combined buffer 256 btstack_assert(sizeof(test_buffer_t) == sizeof(btstack_memory_buffer_t) + sizeof(void *)); 257#endif 258 259''' 260 261init_template = """#if POOL_COUNT > 0 262 btstack_memory_pool_create(&STRUCT_NAME_pool, STRUCT_NAME_storage, POOL_COUNT, sizeof(STRUCT_TYPE)); 263#endif""" 264 265def writeln(f, data): 266 f.write(data + "\n") 267 268def replacePlaceholder(template, struct_name): 269 struct_type = struct_name + '_t' 270 if struct_name.endswith('try'): 271 pool_count = "MAX_NR_" + struct_name.upper()[:-3] + "TRIES" 272 else: 273 pool_count = "MAX_NR_" + struct_name.upper() + "S" 274 pool_count_old_no = pool_count.replace("MAX_NR_", "MAX_NO_") 275 snippet = template.replace("STRUCT_TYPE", struct_type).replace("STRUCT_NAME", struct_name).replace("POOL_COUNT_OLD_NO", pool_count_old_no).replace("POOL_COUNT", pool_count) 276 return snippet 277 278list_of_structs = [ 279 ["hci_connection"], 280 ["l2cap_service", "l2cap_channel"], 281] 282list_of_classic_structs = [ 283 ["rfcomm_multiplexer", "rfcomm_service", "rfcomm_channel"], 284 ["btstack_link_key_db_memory_entry"], 285 ["bnep_service", "bnep_channel"], 286 ["hfp_connection"], 287 ["hid_host_connection"], 288 ["service_record_item"], 289 ["avdtp_stream_endpoint"], 290 ["avdtp_connection"], 291 ["avrcp_connection"], 292 ["avrcp_browsing_connection"], 293] 294list_of_le_structs = [ 295 ["gatt_client", "whitelist_entry", "sm_lookup_entry"], 296] 297list_of_mesh_structs = [ 298 ['mesh_network_pdu', 'mesh_segmented_pdu', 'mesh_upper_transport_pdu', 'mesh_network_key', 'mesh_transport_key', 'mesh_virtual_address', 'mesh_subnet'] 299] 300 301btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') 302file_name = btstack_root + "/src/btstack_memory" 303print ('Generating %s.[h|c]' % file_name) 304 305f = open(file_name+".h", "w") 306writeln(f, copyright) 307writeln(f, hfile_header_begin) 308for struct_names in list_of_structs: 309 writeln(f, "// "+ ", ".join(struct_names)) 310 for struct_name in struct_names: 311 writeln(f, replacePlaceholder(header_template, struct_name)) 312 writeln(f, "") 313writeln(f, "#ifdef ENABLE_CLASSIC") 314for struct_names in list_of_classic_structs: 315 writeln(f, "// "+ ", ".join(struct_names)) 316 for struct_name in struct_names: 317 writeln(f, replacePlaceholder(header_template, struct_name)) 318 writeln(f, "") 319writeln(f, "#endif") 320writeln(f, "#ifdef ENABLE_BLE") 321for struct_names in list_of_le_structs: 322 writeln(f, "// "+ ", ".join(struct_names)) 323 for struct_name in struct_names: 324 writeln(f, replacePlaceholder(header_template, struct_name)) 325writeln(f, "#endif") 326writeln(f, "#ifdef ENABLE_MESH") 327for struct_names in list_of_mesh_structs: 328 writeln(f, "// "+ ", ".join(struct_names)) 329 for struct_name in struct_names: 330 writeln(f, replacePlaceholder(header_template, struct_name)) 331writeln(f, "#endif") 332writeln(f, hfile_header_end) 333f.close(); 334 335 336f = open(file_name+".c", "w") 337writeln(f, copyright) 338writeln(f, cfile_header_begin) 339for struct_names in list_of_structs: 340 for struct_name in struct_names: 341 writeln(f, replacePlaceholder(code_template, struct_name)) 342 writeln(f, "") 343writeln(f, "#ifdef ENABLE_CLASSIC") 344for struct_names in list_of_classic_structs: 345 for struct_name in struct_names: 346 writeln(f, replacePlaceholder(code_template, struct_name)) 347 writeln(f, "") 348writeln(f, "#endif") 349writeln(f, "#ifdef ENABLE_BLE") 350for struct_names in list_of_le_structs: 351 for struct_name in struct_names: 352 writeln(f, replacePlaceholder(code_template, struct_name)) 353 writeln(f, "") 354writeln(f, "#endif") 355writeln(f, "#ifdef ENABLE_MESH") 356for struct_names in list_of_mesh_structs: 357 for struct_name in struct_names: 358 writeln(f, replacePlaceholder(code_template, struct_name)) 359 writeln(f, "") 360writeln(f, "#endif") 361 362f.write(init_header) 363for struct_names in list_of_structs: 364 for struct_name in struct_names: 365 writeln(f, replacePlaceholder(init_template, struct_name)) 366writeln(f, "#ifdef ENABLE_CLASSIC") 367for struct_names in list_of_classic_structs: 368 for struct_name in struct_names: 369 writeln(f, replacePlaceholder(init_template, struct_name)) 370writeln(f, "#endif") 371writeln(f, "#ifdef ENABLE_BLE") 372for struct_names in list_of_le_structs: 373 for struct_name in struct_names: 374 writeln(f, replacePlaceholder(init_template, struct_name)) 375writeln(f, "#endif") 376writeln(f, "#ifdef ENABLE_MESH") 377for struct_names in list_of_mesh_structs: 378 for struct_name in struct_names: 379 writeln(f, replacePlaceholder(init_template, struct_name)) 380writeln(f, "#endif") 381writeln(f, "}") 382f.close(); 383 384# also generate test code 385test_header = """ 386#include <stdint.h> 387#include <stdio.h> 388#include <stdlib.h> 389#include <string.h> 390 391// malloc hook 392static int simulate_no_memory; 393extern "C" void * test_malloc(size_t size); 394void * test_malloc(size_t size){ 395 if (simulate_no_memory) return NULL; 396 return malloc(size); 397} 398 399#include "btstack_config.h" 400 401#include "CppUTest/TestHarness.h" 402#include "CppUTest/CommandLineTestRunner.h" 403 404#include "bluetooth_data_types.h" 405#include "btstack_util.h" 406#include "btstack_memory.h" 407 408 409TEST_GROUP(btstack_memory){ 410 void setup(void){ 411 btstack_memory_init(); 412 simulate_no_memory = 0; 413 } 414}; 415 416#ifdef HAVE_MALLOC 417TEST(btstack_memory, deinit){ 418 // alloc buffers 1,2,3 419 hci_connection_t * buffer_1 = btstack_memory_hci_connection_get(); 420 hci_connection_t * buffer_2 = btstack_memory_hci_connection_get(); 421 hci_connection_t * buffer_3 = btstack_memory_hci_connection_get(); 422 // free first one in list 423 btstack_memory_hci_connection_free(buffer_3); 424 // free second one in list 425 btstack_memory_hci_connection_free(buffer_1); 426 // leave buffer in list 427 (void) buffer_2; 428 btstack_memory_deinit(); 429} 430#endif 431 432""" 433 434test_template = """ 435 436TEST(btstack_memory, STRUCT_NAME_GetAndFree){ 437 STRUCT_NAME_t * context; 438#ifdef HAVE_MALLOC 439 context = btstack_memory_STRUCT_NAME_get(); 440 CHECK(context != NULL); 441 btstack_memory_STRUCT_NAME_free(context); 442#else 443#ifdef POOL_COUNT 444 // single 445 context = btstack_memory_STRUCT_NAME_get(); 446 CHECK(context != NULL); 447 btstack_memory_STRUCT_NAME_free(context); 448#else 449 // none 450 context = btstack_memory_STRUCT_NAME_get(); 451 CHECK(context == NULL); 452 btstack_memory_STRUCT_NAME_free(context); 453#endif 454#endif 455} 456 457TEST(btstack_memory, STRUCT_NAME_NotEnoughBuffers){ 458 STRUCT_NAME_t * context; 459#ifdef HAVE_MALLOC 460 simulate_no_memory = 1; 461#else 462#ifdef POOL_COUNT 463 int i; 464 // alloc all static buffers 465 for (i = 0; i < POOL_COUNT; i++){ 466 context = btstack_memory_STRUCT_NAME_get(); 467 CHECK(context != NULL); 468 } 469#endif 470#endif 471 // get one more 472 context = btstack_memory_STRUCT_NAME_get(); 473 CHECK(context == NULL); 474} 475""" 476 477test_footer = """ 478int main (int argc, const char * argv[]){ 479 return CommandLineTestRunner::RunAllTests(argc, argv); 480} 481""" 482 483file_name = btstack_root + "/test/btstack_memory/btstack_memory_test.c" 484print ('Generating %s' % file_name) 485 486f = open(file_name, "w") 487writeln(f, copyright) 488writeln(f, test_header) 489for struct_names in list_of_structs: 490 for struct_name in struct_names: 491 writeln(f, replacePlaceholder(test_template, struct_name)) 492writeln(f, "#ifdef ENABLE_CLASSIC") 493for struct_names in list_of_classic_structs: 494 for struct_name in struct_names: 495 writeln(f, replacePlaceholder(test_template, struct_name)) 496writeln(f, "#endif") 497writeln(f, "#ifdef ENABLE_BLE") 498for struct_names in list_of_le_structs: 499 for struct_name in struct_names: 500 writeln(f, replacePlaceholder(test_template, struct_name)) 501writeln(f, "#endif") 502writeln(f, "#ifdef ENABLE_MESH") 503for struct_names in list_of_mesh_structs: 504 for struct_name in struct_names: 505 writeln(f, replacePlaceholder(test_template, struct_name)) 506writeln(f, "#endif") 507writeln(f, test_footer)