1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** ThreadX Component */
17 /** */
18 /** Byte Memory */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define TX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "tx_api.h"
29 #include "tx_trace.h"
30 #include "tx_thread.h"
31 #include "tx_byte_pool.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_byte_release PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function returns previously allocated memory to its */
47 /* associated memory byte pool. */
48 /* */
49 /* INPUT */
50 /* */
51 /* memory_ptr Pointer to allocated memory */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* [TX_PTR_ERROR | TX_SUCCESS] Completion status */
56 /* */
57 /* CALLS */
58 /* */
59 /* _tx_thread_system_preempt_check Check for preemption */
60 /* _tx_thread_system_resume Resume thread service */
61 /* _tx_thread_system_ni_resume Non-interruptable resume thread */
62 /* _tx_byte_pool_search Search the byte pool for memory */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Application Code */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
73 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
74 /* resulting in version 6.1 */
75 /* */
76 /**************************************************************************/
_tx_byte_release(VOID * memory_ptr)77 UINT _tx_byte_release(VOID *memory_ptr)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 UINT status;
83 TX_BYTE_POOL *pool_ptr;
84 TX_THREAD *thread_ptr;
85 UCHAR *work_ptr;
86 UCHAR *temp_ptr;
87 UCHAR *next_block_ptr;
88 TX_THREAD *susp_thread_ptr;
89 UINT suspended_count;
90 TX_THREAD *next_thread;
91 TX_THREAD *previous_thread;
92 ULONG memory_size;
93 ALIGN_TYPE *free_ptr;
94 TX_BYTE_POOL **byte_pool_ptr;
95 UCHAR **block_link_ptr;
96 UCHAR **suspend_info_ptr;
97
98
99 /* Default to successful status. */
100 status = TX_SUCCESS;
101
102 /* Set the pool pointer to NULL. */
103 pool_ptr = TX_NULL;
104
105 /* Lockout interrupts. */
106 TX_DISABLE
107
108 /* Determine if the memory pointer is valid. */
109 work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(memory_ptr);
110 if (work_ptr != TX_NULL)
111 {
112
113 /* Back off the memory pointer to pickup its header. */
114 work_ptr = TX_UCHAR_POINTER_SUB(work_ptr, ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE))));
115
116 /* There is a pointer, pickup the pool pointer address. */
117 temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
118 free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
119 if ((*free_ptr) != TX_BYTE_BLOCK_FREE)
120 {
121
122 /* Pickup the pool pointer. */
123 temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
124 byte_pool_ptr = TX_UCHAR_TO_INDIRECT_BYTE_POOL_POINTER(temp_ptr);
125 pool_ptr = *byte_pool_ptr;
126
127 /* See if we have a valid pool pointer. */
128 if (pool_ptr == TX_NULL)
129 {
130
131 /* Return pointer error. */
132 status = TX_PTR_ERROR;
133 }
134 else
135 {
136
137 /* See if we have a valid pool. */
138 if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID)
139 {
140
141 /* Return pointer error. */
142 status = TX_PTR_ERROR;
143
144 /* Reset the pool pointer is NULL. */
145 pool_ptr = TX_NULL;
146 }
147 }
148 }
149 else
150 {
151
152 /* Return pointer error. */
153 status = TX_PTR_ERROR;
154 }
155 }
156 else
157 {
158
159 /* Return pointer error. */
160 status = TX_PTR_ERROR;
161 }
162
163 /* Determine if the pointer is valid. */
164 if (pool_ptr == TX_NULL)
165 {
166
167 /* Restore interrupts. */
168 TX_RESTORE
169 }
170 else
171 {
172
173 /* At this point, we know that the pointer is valid. */
174
175 /* Pickup thread pointer. */
176 TX_THREAD_GET_CURRENT(thread_ptr)
177
178 /* Indicate that this thread is the current owner. */
179 pool_ptr -> tx_byte_pool_owner = thread_ptr;
180
181 #ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
182
183 /* Increment the total release counter. */
184 _tx_byte_pool_performance_release_count++;
185
186 /* Increment the number of releases on this pool. */
187 pool_ptr -> tx_byte_pool_performance_release_count++;
188 #endif
189
190 /* If trace is enabled, insert this event into the trace buffer. */
191 TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_RELEASE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(memory_ptr), pool_ptr -> tx_byte_pool_suspended_count, pool_ptr -> tx_byte_pool_available, TX_TRACE_BYTE_POOL_EVENTS)
192
193 /* Log this kernel call. */
194 TX_EL_BYTE_RELEASE_INSERT
195
196 /* Release the memory. */
197 temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
198 free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
199 *free_ptr = TX_BYTE_BLOCK_FREE;
200
201 /* Update the number of available bytes in the pool. */
202 block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
203 next_block_ptr = *block_link_ptr;
204 pool_ptr -> tx_byte_pool_available =
205 pool_ptr -> tx_byte_pool_available + TX_UCHAR_POINTER_DIF(next_block_ptr, work_ptr);
206
207 /* Determine if the free block is prior to current search pointer. */
208 if (work_ptr < (pool_ptr -> tx_byte_pool_search))
209 {
210
211 /* Yes, update the search pointer to the released block. */
212 pool_ptr -> tx_byte_pool_search = work_ptr;
213 }
214
215 /* Determine if there are threads suspended on this byte pool. */
216 if (pool_ptr -> tx_byte_pool_suspended_count != TX_NO_SUSPENSIONS)
217 {
218
219 /* Now examine the suspension list to find threads waiting for
220 memory. Maybe it is now available! */
221 while (pool_ptr -> tx_byte_pool_suspended_count != TX_NO_SUSPENSIONS)
222 {
223
224 /* Pickup the first suspended thread pointer. */
225 susp_thread_ptr = pool_ptr -> tx_byte_pool_suspension_list;
226
227 /* Pickup the size of the memory the thread is requesting. */
228 memory_size = susp_thread_ptr -> tx_thread_suspend_info;
229
230 /* Restore interrupts. */
231 TX_RESTORE
232
233 /* See if the request can be satisfied. */
234 work_ptr = _tx_byte_pool_search(pool_ptr, memory_size);
235
236 /* Optional processing extension. */
237 TX_BYTE_RELEASE_EXTENSION
238
239 /* Disable interrupts. */
240 TX_DISABLE
241
242 /* Indicate that this thread is the current owner. */
243 pool_ptr -> tx_byte_pool_owner = thread_ptr;
244
245 /* If there is not enough memory, break this loop! */
246 if (work_ptr == TX_NULL)
247 {
248
249 /* Break out of the loop. */
250 break;
251 }
252
253 /* Check to make sure the thread is still suspended. */
254 if (susp_thread_ptr == pool_ptr -> tx_byte_pool_suspension_list)
255 {
256
257 /* Also, makes sure the memory size is the same. */
258 if (susp_thread_ptr -> tx_thread_suspend_info == memory_size)
259 {
260
261 /* Remove the suspended thread from the list. */
262
263 /* Decrement the number of threads suspended. */
264 pool_ptr -> tx_byte_pool_suspended_count--;
265
266 /* Pickup the suspended count. */
267 suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
268
269 /* See if this is the only suspended thread on the list. */
270 if (suspended_count == TX_NO_SUSPENSIONS)
271 {
272
273 /* Yes, the only suspended thread. */
274
275 /* Update the head pointer. */
276 pool_ptr -> tx_byte_pool_suspension_list = TX_NULL;
277 }
278 else
279 {
280
281 /* At least one more thread is on the same expiration list. */
282
283 /* Update the list head pointer. */
284 next_thread = susp_thread_ptr -> tx_thread_suspended_next;
285 pool_ptr -> tx_byte_pool_suspension_list = next_thread;
286
287 /* Update the links of the adjacent threads. */
288 previous_thread = susp_thread_ptr -> tx_thread_suspended_previous;
289 next_thread -> tx_thread_suspended_previous = previous_thread;
290 previous_thread -> tx_thread_suspended_next = next_thread;
291 }
292
293 /* Prepare for resumption of the thread. */
294
295 /* Clear cleanup routine to avoid timeout. */
296 susp_thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
297
298 /* Return this block pointer to the suspended thread waiting for
299 a block. */
300 suspend_info_ptr = TX_VOID_TO_INDIRECT_UCHAR_POINTER_CONVERT(susp_thread_ptr -> tx_thread_additional_suspend_info);
301 *suspend_info_ptr = work_ptr;
302
303 /* Clear the memory pointer to indicate that it was given to the suspended thread. */
304 work_ptr = TX_NULL;
305
306 /* Put return status into the thread control block. */
307 susp_thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
308
309 #ifdef TX_NOT_INTERRUPTABLE
310
311 /* Resume the thread! */
312 _tx_thread_system_ni_resume(susp_thread_ptr);
313
314 /* Restore interrupts. */
315 TX_RESTORE
316 #else
317 /* Temporarily disable preemption. */
318 _tx_thread_preempt_disable++;
319
320 /* Restore interrupts. */
321 TX_RESTORE
322
323 /* Resume thread. */
324 _tx_thread_system_resume(susp_thread_ptr);
325 #endif
326
327 /* Lockout interrupts. */
328 TX_DISABLE
329 }
330 }
331
332 /* Determine if the memory was given to the suspended thread. */
333 if (work_ptr != TX_NULL)
334 {
335
336 /* No, it wasn't given to the suspended thread. */
337
338 /* Put the memory back on the available list since this thread is no longer
339 suspended. */
340 work_ptr = TX_UCHAR_POINTER_SUB(work_ptr, (((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)))));
341 temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
342 free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
343 *free_ptr = TX_BYTE_BLOCK_FREE;
344
345 /* Update the number of available bytes in the pool. */
346 block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
347 next_block_ptr = *block_link_ptr;
348 pool_ptr -> tx_byte_pool_available =
349 pool_ptr -> tx_byte_pool_available + TX_UCHAR_POINTER_DIF(next_block_ptr, work_ptr);
350
351 /* Determine if the current pointer is before the search pointer. */
352 if (work_ptr < (pool_ptr -> tx_byte_pool_search))
353 {
354
355 /* Yes, update the search pointer. */
356 pool_ptr -> tx_byte_pool_search = work_ptr;
357 }
358 }
359 }
360
361 /* Restore interrupts. */
362 TX_RESTORE
363
364 /* Check for preemption. */
365 _tx_thread_system_preempt_check();
366 }
367 else
368 {
369
370 /* No, threads suspended, restore interrupts. */
371 TX_RESTORE
372 }
373 }
374
375 /* Return completion status. */
376 return(status);
377 }
378
379