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