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 /**   Semaphore                                                           */
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_semaphore.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _tx_semaphore_ceiling_put                           PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function puts an instance into the specified counting          */
47 /*    semaphore up to the specified semaphore ceiling.                    */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    semaphore_ptr                         Pointer to semaphore          */
52 /*    ceiling                               Maximum value of semaphore    */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    status                                Completion status             */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _tx_thread_system_resume              Resume thread service         */
61 /*    _tx_thread_system_ni_resume           Non-interruptable resume      */
62 /*                                            thread                      */
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_semaphore_ceiling_put(TX_SEMAPHORE * semaphore_ptr,ULONG ceiling)77 UINT  _tx_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling)
78 {
79 
80 TX_INTERRUPT_SAVE_AREA
81 
82 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
83 VOID            (*semaphore_put_notify)(struct TX_SEMAPHORE_STRUCT *notify_semaphore_ptr);
84 #endif
85 
86 TX_THREAD       *thread_ptr;
87 UINT            suspended_count;
88 TX_THREAD       *next_thread;
89 TX_THREAD       *previous_thread;
90 UINT            status;
91 
92 
93     /* Default the status to TX_SUCCESS.  */
94     status =  TX_SUCCESS;
95 
96     /* Disable interrupts to put an instance back to the semaphore.  */
97     TX_DISABLE
98 
99 #ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
100 
101     /* Increment the total semaphore put counter.  */
102     _tx_semaphore_performance_put_count++;
103 
104     /* Increment the number of puts on this semaphore.  */
105     semaphore_ptr -> tx_semaphore_performance_put_count++;
106 #endif
107 
108     /* If trace is enabled, insert this event into the trace buffer.  */
109     TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_CEILING_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count, semaphore_ptr -> tx_semaphore_suspended_count, ceiling, TX_TRACE_SEMAPHORE_EVENTS)
110 
111     /* Log this kernel call.  */
112     TX_EL_SEMAPHORE_CEILING_PUT_INSERT
113 
114     /* Pickup the number of suspended threads.  */
115     suspended_count =  semaphore_ptr -> tx_semaphore_suspended_count;
116 
117     /* Determine if there are any threads suspended on the semaphore.  */
118     if (suspended_count == TX_NO_SUSPENSIONS)
119     {
120 
121         /* Determine if the ceiling has been exceeded.  */
122         if (semaphore_ptr -> tx_semaphore_count >= ceiling)
123         {
124 
125             /* Restore interrupts.  */
126             TX_RESTORE
127 
128             /* Return an error.  */
129             status =  TX_CEILING_EXCEEDED;
130         }
131         else
132         {
133 
134             /* Increment the semaphore count.  */
135             semaphore_ptr -> tx_semaphore_count++;
136 
137 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
138 
139             /* Pickup the application notify function.  */
140             semaphore_put_notify =  semaphore_ptr -> tx_semaphore_put_notify;
141 #endif
142 
143             /* Restore interrupts.  */
144             TX_RESTORE
145 
146 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
147 
148             /* Determine if notification is required.  */
149             if (semaphore_put_notify != TX_NULL)
150             {
151 
152                 /* Yes, call the appropriate notify callback function.  */
153                 (semaphore_put_notify)(semaphore_ptr);
154             }
155 #endif
156 
157             /* Return successful completion status.  */
158             status =  TX_SUCCESS;
159         }
160     }
161     else
162     {
163 
164         /* Remove the suspended thread from the list.  */
165 
166         /* Pickup the pointer to the first suspended thread.  */
167         thread_ptr =  semaphore_ptr -> tx_semaphore_suspension_list;
168 
169         /* See if this is the only suspended thread on the list.  */
170         suspended_count--;
171         if (suspended_count == TX_NO_SUSPENSIONS)
172         {
173 
174             /* Yes, the only suspended thread.  */
175 
176             /* Update the head pointer.  */
177             semaphore_ptr -> tx_semaphore_suspension_list =  TX_NULL;
178         }
179         else
180         {
181 
182             /* At least one more thread is on the same expiration list.  */
183 
184             /* Update the list head pointer.  */
185             next_thread =                                     thread_ptr -> tx_thread_suspended_next;
186             semaphore_ptr -> tx_semaphore_suspension_list =   next_thread;
187 
188             /* Update the links of the adjacent threads.  */
189             previous_thread =                               thread_ptr -> tx_thread_suspended_previous;
190             next_thread -> tx_thread_suspended_previous =   previous_thread;
191             previous_thread -> tx_thread_suspended_next =   next_thread;
192         }
193 
194         /* Decrement the suspension count.  */
195         semaphore_ptr -> tx_semaphore_suspended_count =  suspended_count;
196 
197         /* Prepare for resumption of the first thread.  */
198 
199         /* Clear cleanup routine to avoid timeout.  */
200         thread_ptr -> tx_thread_suspend_cleanup =  TX_NULL;
201 
202         /* Put return status into the thread control block.  */
203         thread_ptr -> tx_thread_suspend_status =  TX_SUCCESS;
204 
205 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
206 
207         /* Pickup the application notify function.  */
208         semaphore_put_notify =  semaphore_ptr -> tx_semaphore_put_notify;
209 #endif
210 
211 #ifdef TX_NOT_INTERRUPTABLE
212 
213         /* Resume the thread!  */
214         _tx_thread_system_ni_resume(thread_ptr);
215 
216         /* Restore interrupts.  */
217         TX_RESTORE
218 #else
219 
220         /* Temporarily disable preemption.  */
221         _tx_thread_preempt_disable++;
222 
223         /* Restore interrupts.  */
224         TX_RESTORE
225 
226         /* Resume thread.  */
227         _tx_thread_system_resume(thread_ptr);
228 #endif
229 
230 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
231 
232         /* Determine if notification is required.  */
233         if (semaphore_put_notify != TX_NULL)
234         {
235 
236             /* Yes, call the appropriate notify callback function.  */
237             (semaphore_put_notify)(semaphore_ptr);
238         }
239 #endif
240     }
241 
242     /* Return successful completion.  */
243     return(status);
244 }
245 
246