1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** ThreadX Component */
16 /** */
17 /** Block Pool */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define TX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #include "tx_trace.h"
29 #include "tx_block_pool.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _tx_block_pool_create PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function creates a pool of fixed-size memory blocks in the */
45 /* specified memory area. */
46 /* */
47 /* INPUT */
48 /* */
49 /* pool_ptr Pointer to pool control block */
50 /* name_ptr Pointer to block pool name */
51 /* block_size Number of bytes in each block */
52 /* pool_start Address of beginning of pool area */
53 /* pool_size Number of bytes in the block pool */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* TX_SUCCESS Successful completion status */
58 /* */
59 /* CALLS */
60 /* */
61 /* None */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
72 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* */
75 /**************************************************************************/
_tx_block_pool_create(TX_BLOCK_POOL * pool_ptr,CHAR * name_ptr,ULONG block_size,VOID * pool_start,ULONG pool_size)76 UINT _tx_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
77 VOID *pool_start, ULONG pool_size)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 UINT blocks;
83 UINT status;
84 ULONG total_blocks;
85 UCHAR *block_ptr;
86 UCHAR **block_link_ptr;
87 UCHAR *next_block_ptr;
88 TX_BLOCK_POOL *next_pool;
89 TX_BLOCK_POOL *previous_pool;
90
91
92 /* Initialize block pool control block to all zeros. */
93 TX_MEMSET(pool_ptr, 0, (sizeof(TX_BLOCK_POOL)));
94
95 /* Round the block size up to something that is evenly divisible by
96 an ALIGN_TYPE (typically this is a 32-bit ULONG). This helps guarantee proper alignment. */
97 block_size = (((block_size + (sizeof(ALIGN_TYPE))) - ((ALIGN_TYPE) 1))/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
98
99 /* Round the pool size down to something that is evenly divisible by
100 an ALIGN_TYPE (typically this is a 32-bit ULONG). */
101 pool_size = (pool_size/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
102
103 /* Setup the basic block pool fields. */
104 pool_ptr -> tx_block_pool_name = name_ptr;
105 pool_ptr -> tx_block_pool_start = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
106 pool_ptr -> tx_block_pool_size = pool_size;
107 pool_ptr -> tx_block_pool_block_size = (UINT) block_size;
108
109 /* Calculate the total number of blocks. */
110 total_blocks = pool_size/(block_size + (sizeof(UCHAR *)));
111
112 /* Walk through the pool area, setting up the available block list. */
113 blocks = ((UINT) 0);
114 block_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
115 next_block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, (block_size + (sizeof(UCHAR *))));
116 while(blocks < (UINT) total_blocks)
117 {
118
119 /* Yes, we have another block. Increment the block count. */
120 blocks++;
121
122 /* Setup the link to the next block. */
123 block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
124 *block_link_ptr = next_block_ptr;
125
126 /* Advance to the next block. */
127 block_ptr = next_block_ptr;
128
129 /* Update the next block pointer. */
130 next_block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, (block_size + (sizeof(UCHAR *))));
131 }
132
133 /* Save the remaining information in the pool control block. */
134 pool_ptr -> tx_block_pool_available = blocks;
135 pool_ptr -> tx_block_pool_total = blocks;
136
137 /* Quickly check to make sure at least one block is in the pool. */
138 if (blocks != ((UINT) 0))
139 {
140
141 /* Backup to the last block in the pool. */
142 block_ptr = TX_UCHAR_POINTER_SUB(block_ptr,(block_size + (sizeof(UCHAR *))));
143
144 /* Set the last block's forward pointer to NULL. */
145 block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
146 *block_link_ptr = TX_NULL;
147
148 /* Setup the starting pool address. */
149 pool_ptr -> tx_block_pool_available_list = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
150
151 /* Disable interrupts to place the block pool on the created list. */
152 TX_DISABLE
153
154 /* Setup the block pool ID to make it valid. */
155 pool_ptr -> tx_block_pool_id = TX_BLOCK_POOL_ID;
156
157 /* Place the block pool on the list of created block pools. First,
158 check for an empty list. */
159 if (_tx_block_pool_created_count == TX_EMPTY)
160 {
161
162 /* The created block pool list is empty. Add block pool to empty list. */
163 _tx_block_pool_created_ptr = pool_ptr;
164 pool_ptr -> tx_block_pool_created_next = pool_ptr;
165 pool_ptr -> tx_block_pool_created_previous = pool_ptr;
166 }
167 else
168 {
169
170 /* This list is not NULL, add to the end of the list. */
171 next_pool = _tx_block_pool_created_ptr;
172 previous_pool = next_pool -> tx_block_pool_created_previous;
173
174 /* Place the new block pool in the list. */
175 next_pool -> tx_block_pool_created_previous = pool_ptr;
176 previous_pool -> tx_block_pool_created_next = pool_ptr;
177
178 /* Setup this block pool's created links. */
179 pool_ptr -> tx_block_pool_created_previous = previous_pool;
180 pool_ptr -> tx_block_pool_created_next = next_pool;
181 }
182
183 /* Increment the created count. */
184 _tx_block_pool_created_count++;
185
186 /* Optional block pool create extended processing. */
187 TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
188
189 /* If trace is enabled, register this object. */
190 TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_BLOCK_POOL, pool_ptr, name_ptr, pool_size, block_size)
191
192 /* If trace is enabled, insert this event into the trace buffer. */
193 TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_CREATE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(pool_start), blocks, block_size, TX_TRACE_BLOCK_POOL_EVENTS)
194
195 /* Log this kernel call. */
196 TX_EL_BLOCK_POOL_CREATE_INSERT
197
198 /* Restore interrupts. */
199 TX_RESTORE
200
201 /* Return successful status. */
202 status = TX_SUCCESS;
203 }
204 else
205 {
206
207 /* Not enough memory for one block, return appropriate error. */
208 status = TX_SIZE_ERROR;
209 }
210
211 /* Return completion status. */
212 return(status);
213 }
214
215