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