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_get PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function gets an instance from the specified counting */
47 /* semaphore. */
48 /* */
49 /* INPUT */
50 /* */
51 /* semaphore_ptr Pointer to semaphore control block*/
52 /* wait_option Suspension option */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _tx_thread_system_suspend Suspend thread service */
61 /* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
72 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* */
75 /**************************************************************************/
_tx_semaphore_get(TX_SEMAPHORE * semaphore_ptr,ULONG wait_option)76 UINT _tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option)
77 {
78
79 TX_INTERRUPT_SAVE_AREA
80
81 TX_THREAD *thread_ptr;
82 TX_THREAD *next_thread;
83 TX_THREAD *previous_thread;
84 UINT status;
85
86
87 /* Default the status to TX_SUCCESS. */
88 status = TX_SUCCESS;
89
90 /* Disable interrupts to get an instance from the semaphore. */
91 TX_DISABLE
92
93 #ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
94
95 /* Increment the total semaphore get counter. */
96 _tx_semaphore_performance_get_count++;
97
98 /* Increment the number of attempts to get this semaphore. */
99 semaphore_ptr -> tx_semaphore_performance_get_count++;
100 #endif
101
102 /* If trace is enabled, insert this event into the trace buffer. */
103 TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_GET, semaphore_ptr, wait_option, semaphore_ptr -> tx_semaphore_count, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_SEMAPHORE_EVENTS)
104
105 /* Log this kernel call. */
106 TX_EL_SEMAPHORE_GET_INSERT
107
108 /* Determine if there is an instance of the semaphore. */
109 if (semaphore_ptr -> tx_semaphore_count != ((ULONG) 0))
110 {
111
112 /* Decrement the semaphore count. */
113 semaphore_ptr -> tx_semaphore_count--;
114
115 /* Restore interrupts. */
116 TX_RESTORE
117 }
118
119 /* Determine if the request specifies suspension. */
120 else if (wait_option != TX_NO_WAIT)
121 {
122
123 /* Determine if the preempt disable flag is non-zero. */
124 if (_tx_thread_preempt_disable != ((UINT) 0))
125 {
126
127 /* Restore interrupts. */
128 TX_RESTORE
129
130 /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
131 status = TX_NO_INSTANCE;
132 }
133 else
134 {
135
136 /* Prepare for suspension of this thread. */
137
138 #ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
139
140 /* Increment the total semaphore suspensions counter. */
141 _tx_semaphore_performance_suspension_count++;
142
143 /* Increment the number of suspensions on this semaphore. */
144 semaphore_ptr -> tx_semaphore_performance_suspension_count++;
145 #endif
146
147 /* Pickup thread pointer. */
148 TX_THREAD_GET_CURRENT(thread_ptr)
149
150 /* Setup cleanup routine pointer. */
151 thread_ptr -> tx_thread_suspend_cleanup = &(_tx_semaphore_cleanup);
152
153 /* Setup cleanup information, i.e. this semaphore control
154 block. */
155 thread_ptr -> tx_thread_suspend_control_block = (VOID *) semaphore_ptr;
156
157 #ifndef TX_NOT_INTERRUPTABLE
158
159 /* Increment the suspension sequence number, which is used to identify
160 this suspension event. */
161 thread_ptr -> tx_thread_suspension_sequence++;
162 #endif
163
164 /* Setup suspension list. */
165 if (semaphore_ptr -> tx_semaphore_suspended_count == TX_NO_SUSPENSIONS)
166 {
167
168 /* No other threads are suspended. Setup the head pointer and
169 just setup this threads pointers to itself. */
170 semaphore_ptr -> tx_semaphore_suspension_list = thread_ptr;
171 thread_ptr -> tx_thread_suspended_next = thread_ptr;
172 thread_ptr -> tx_thread_suspended_previous = thread_ptr;
173 }
174 else
175 {
176
177 /* This list is not NULL, add current thread to the end. */
178 next_thread = semaphore_ptr -> tx_semaphore_suspension_list;
179 thread_ptr -> tx_thread_suspended_next = next_thread;
180 previous_thread = next_thread -> tx_thread_suspended_previous;
181 thread_ptr -> tx_thread_suspended_previous = previous_thread;
182 previous_thread -> tx_thread_suspended_next = thread_ptr;
183 next_thread -> tx_thread_suspended_previous = thread_ptr;
184 }
185
186 /* Increment the number of suspensions. */
187 semaphore_ptr -> tx_semaphore_suspended_count++;
188
189 /* Set the state to suspended. */
190 thread_ptr -> tx_thread_state = TX_SEMAPHORE_SUSP;
191
192 #ifdef TX_NOT_INTERRUPTABLE
193
194 /* Call actual non-interruptable thread suspension routine. */
195 _tx_thread_system_ni_suspend(thread_ptr, wait_option);
196
197 /* Restore interrupts. */
198 TX_RESTORE
199 #else
200
201 /* Set the suspending flag. */
202 thread_ptr -> tx_thread_suspending = TX_TRUE;
203
204 /* Setup the timeout period. */
205 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
206
207 /* Temporarily disable preemption. */
208 _tx_thread_preempt_disable++;
209
210 /* Restore interrupts. */
211 TX_RESTORE
212
213 /* Call actual thread suspension routine. */
214 _tx_thread_system_suspend(thread_ptr);
215 #endif
216
217 /* Return the completion status. */
218 status = thread_ptr -> tx_thread_suspend_status;
219 }
220 }
221 else
222 {
223
224 /* Restore interrupts. */
225 TX_RESTORE
226
227 /* Immediate return, return error completion. */
228 status = TX_NO_INSTANCE;
229 }
230
231 /* Return completion status. */
232 return(status);
233 }
234
235