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 /** Byte Memory */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define TX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #ifdef TX_ENABLE_EVENT_TRACE
29 #include "tx_trace.h"
30 #endif
31 #include "tx_thread.h"
32 #include "tx_byte_pool.h"
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _tx_byte_allocate PORTABLE C */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function allocates bytes from the specified memory byte */
48 /* pool. */
49 /* */
50 /* INPUT */
51 /* */
52 /* pool_ptr Pointer to pool control block */
53 /* memory_ptr Pointer to place allocated bytes */
54 /* pointer */
55 /* memory_size Number of bytes to allocate */
56 /* wait_option Suspension option */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* status Completion status */
61 /* */
62 /* CALLS */
63 /* */
64 /* _tx_thread_system_suspend Suspend thread service */
65 /* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
66 /* _tx_byte_pool_search Search byte pool for memory */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* Application Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
77 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* */
80 /**************************************************************************/
_tx_byte_allocate(TX_BYTE_POOL * pool_ptr,VOID ** memory_ptr,ULONG memory_size,ULONG wait_option)81 UINT _tx_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size, ULONG wait_option)
82 {
83
84 TX_INTERRUPT_SAVE_AREA
85
86 UINT status;
87 TX_THREAD *thread_ptr;
88 UCHAR *work_ptr;
89 UINT suspended_count;
90 TX_THREAD *next_thread;
91 TX_THREAD *previous_thread;
92 UINT finished;
93 #ifdef TX_ENABLE_EVENT_TRACE
94 TX_TRACE_BUFFER_ENTRY *entry_ptr;
95 ULONG time_stamp = ((ULONG) 0);
96 #endif
97 #ifdef TX_ENABLE_EVENT_LOGGING
98 UCHAR *log_entry_ptr;
99 ULONG upper_tbu;
100 ULONG lower_tbu;
101 #endif
102
103
104 /* Round the memory size up to the next size that is evenly divisible by
105 an ALIGN_TYPE (this is typically a 32-bit ULONG). This guarantees proper alignment. */
106 memory_size = (((memory_size + (sizeof(ALIGN_TYPE)))-((ALIGN_TYPE) 1))/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
107
108 /* Disable interrupts. */
109 TX_DISABLE
110
111 /* Pickup thread pointer. */
112 TX_THREAD_GET_CURRENT(thread_ptr)
113
114 #ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
115
116 /* Increment the total allocations counter. */
117 _tx_byte_pool_performance_allocate_count++;
118
119 /* Increment the number of allocations on this pool. */
120 pool_ptr -> tx_byte_pool_performance_allocate_count++;
121 #endif
122
123 #ifdef TX_ENABLE_EVENT_TRACE
124
125 /* If trace is enabled, save the current event pointer. */
126 entry_ptr = _tx_trace_buffer_current_ptr;
127
128 /* If trace is enabled, insert this event into the trace buffer. */
129 TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_ALLOCATE, pool_ptr, 0, memory_size, wait_option, TX_TRACE_BYTE_POOL_EVENTS)
130
131 /* Save the time stamp for later comparison to verify that
132 the event hasn't been overwritten by the time the allocate
133 call succeeds. */
134 if (entry_ptr != TX_NULL)
135 {
136
137 time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
138 }
139 #endif
140
141 #ifdef TX_ENABLE_EVENT_LOGGING
142 log_entry_ptr = *(UCHAR **) _tx_el_current_event;
143
144 /* Log this kernel call. */
145 TX_EL_BYTE_ALLOCATE_INSERT
146
147 /* Store -1 in the fourth event slot. */
148 *((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) -1;
149
150 /* Save the time stamp for later comparison to verify that
151 the event hasn't been overwritten by the time the allocate
152 call succeeds. */
153 lower_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET));
154 upper_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET));
155 #endif
156
157 /* Set the search finished flag to false. */
158 finished = TX_FALSE;
159
160 /* Loop to handle cases where the owner of the pool changed. */
161 do
162 {
163
164 /* Indicate that this thread is the current owner. */
165 pool_ptr -> tx_byte_pool_owner = thread_ptr;
166
167 /* Restore interrupts. */
168 TX_RESTORE
169
170 /* At this point, the executing thread owns the pool and can perform a search
171 for free memory. */
172 work_ptr = _tx_byte_pool_search(pool_ptr, memory_size);
173
174 /* Optional processing extension. */
175 TX_BYTE_ALLOCATE_EXTENSION
176
177 /* Lockout interrupts. */
178 TX_DISABLE
179
180 /* Determine if we are finished. */
181 if (work_ptr != TX_NULL)
182 {
183
184 /* Yes, we have found a block the search is finished. */
185 finished = TX_TRUE;
186 }
187 else
188 {
189
190 /* No block was found, does this thread still own the pool? */
191 if (pool_ptr -> tx_byte_pool_owner == thread_ptr)
192 {
193
194 /* Yes, then we have looked through the entire pool and haven't found the memory. */
195 finished = TX_TRUE;
196 }
197 }
198
199 } while (finished == TX_FALSE);
200
201 /* Copy the pointer into the return destination. */
202 *memory_ptr = (VOID *) work_ptr;
203
204 /* Determine if memory was found. */
205 if (work_ptr != TX_NULL)
206 {
207
208 #ifdef TX_ENABLE_EVENT_TRACE
209
210 /* Check that the event time stamp is unchanged. A different
211 timestamp means that a later event wrote over the byte
212 allocate event. In that case, do nothing here. */
213 if (entry_ptr != TX_NULL)
214 {
215
216 /* Is the timestamp the same? */
217 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
218 {
219
220 /* Timestamp is the same, update the entry with the address. */
221 #ifdef TX_MISRA_ENABLE
222 entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
223 #else
224 entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
225 #endif
226 }
227 }
228 #endif
229
230 #ifdef TX_ENABLE_EVENT_LOGGING
231 /* Check that the event time stamp is unchanged. A different
232 timestamp means that a later event wrote over the byte
233 allocate event. In that case, do nothing here. */
234 if (lower_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) &&
235 upper_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)))
236 {
237 /* Store the address of the allocated fragment. */
238 *((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) *memory_ptr;
239 }
240 #endif
241
242 /* Restore interrupts. */
243 TX_RESTORE
244
245 /* Set the status to success. */
246 status = TX_SUCCESS;
247 }
248 else
249 {
250
251 /* No memory of sufficient size was found... */
252
253 /* Determine if the request specifies suspension. */
254 if (wait_option != TX_NO_WAIT)
255 {
256
257 /* Determine if the preempt disable flag is non-zero. */
258 if (_tx_thread_preempt_disable != ((UINT) 0))
259 {
260
261 /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
262 status = TX_NO_MEMORY;
263
264 /* Restore interrupts. */
265 TX_RESTORE
266 }
267 else
268 {
269
270 /* Prepare for suspension of this thread. */
271
272 #ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
273
274 /* Increment the total suspensions counter. */
275 _tx_byte_pool_performance_suspension_count++;
276
277 /* Increment the number of suspensions on this pool. */
278 pool_ptr -> tx_byte_pool_performance_suspension_count++;
279 #endif
280
281 /* Setup cleanup routine pointer. */
282 thread_ptr -> tx_thread_suspend_cleanup = &(_tx_byte_pool_cleanup);
283
284 /* Setup cleanup information, i.e. this pool control
285 block. */
286 thread_ptr -> tx_thread_suspend_control_block = (VOID *) pool_ptr;
287
288 /* Save the return memory pointer address as well. */
289 thread_ptr -> tx_thread_additional_suspend_info = (VOID *) memory_ptr;
290
291 /* Save the byte size requested. */
292 thread_ptr -> tx_thread_suspend_info = memory_size;
293
294 #ifndef TX_NOT_INTERRUPTABLE
295
296 /* Increment the suspension sequence number, which is used to identify
297 this suspension event. */
298 thread_ptr -> tx_thread_suspension_sequence++;
299 #endif
300
301 /* Pickup the number of suspended threads. */
302 suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
303
304 /* Increment the suspension count. */
305 (pool_ptr -> tx_byte_pool_suspended_count)++;
306
307 /* Setup suspension list. */
308 if (suspended_count == TX_NO_SUSPENSIONS)
309 {
310
311 /* No other threads are suspended. Setup the head pointer and
312 just setup this threads pointers to itself. */
313 pool_ptr -> tx_byte_pool_suspension_list = thread_ptr;
314 thread_ptr -> tx_thread_suspended_next = thread_ptr;
315 thread_ptr -> tx_thread_suspended_previous = thread_ptr;
316 }
317 else
318 {
319
320 /* This list is not NULL, add current thread to the end. */
321 next_thread = pool_ptr -> tx_byte_pool_suspension_list;
322 thread_ptr -> tx_thread_suspended_next = next_thread;
323 previous_thread = next_thread -> tx_thread_suspended_previous;
324 thread_ptr -> tx_thread_suspended_previous = previous_thread;
325 previous_thread -> tx_thread_suspended_next = thread_ptr;
326 next_thread -> tx_thread_suspended_previous = thread_ptr;
327 }
328
329 /* Set the state to suspended. */
330 thread_ptr -> tx_thread_state = TX_BYTE_MEMORY;
331
332 #ifdef TX_NOT_INTERRUPTABLE
333
334 /* Call actual non-interruptable thread suspension routine. */
335 _tx_thread_system_ni_suspend(thread_ptr, wait_option);
336
337 /* Restore interrupts. */
338 TX_RESTORE
339 #else
340
341 /* Set the suspending flag. */
342 thread_ptr -> tx_thread_suspending = TX_TRUE;
343
344 /* Setup the timeout period. */
345 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
346
347 /* Temporarily disable preemption. */
348 _tx_thread_preempt_disable++;
349
350 /* Restore interrupts. */
351 TX_RESTORE
352
353 /* Call actual thread suspension routine. */
354 _tx_thread_system_suspend(thread_ptr);
355 #endif
356
357 #ifdef TX_ENABLE_EVENT_TRACE
358
359 /* Check that the event time stamp is unchanged. A different
360 timestamp means that a later event wrote over the byte
361 allocate event. In that case, do nothing here. */
362 if (entry_ptr != TX_NULL)
363 {
364
365 /* Is the timestamp the same? */
366 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
367 {
368
369 /* Timestamp is the same, update the entry with the address. */
370 #ifdef TX_MISRA_ENABLE
371 entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
372 #else
373 entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
374 #endif
375 }
376 }
377 #endif
378
379 #ifdef TX_ENABLE_EVENT_LOGGING
380 /* Check that the event time stamp is unchanged. A different
381 timestamp means that a later event wrote over the byte
382 allocate event. In that case, do nothing here. */
383 if (lower_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) &&
384 upper_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)))
385 {
386
387 /* Store the address of the allocated fragment. */
388 *((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) *memory_ptr;
389 }
390 #endif
391
392 /* Return the completion status. */
393 status = thread_ptr -> tx_thread_suspend_status;
394 }
395 }
396 else
397 {
398
399 /* Restore interrupts. */
400 TX_RESTORE
401
402 /* Immediate return, return error completion. */
403 status = TX_NO_MEMORY;
404 }
405 }
406
407 /* Return completion status. */
408 return(status);
409 }
410
411