|
0
|
1 //========================================================================== |
|
|
2 // |
|
2
|
3 // sync/cnt_sem2.cxx |
|
0
|
4 // |
|
2
|
5 // Counting semaphore implementation |
|
0
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
2
|
32 // Author(s): nickg |
|
|
33 // Contributors: nickg |
|
|
34 // Date: 1997-09-24 |
|
|
35 // Purpose: Cyg_Counting_Semaphore implementation |
|
|
36 // Description: This file contains the implementations of the counting semaphore |
|
0
|
37 // class. |
|
|
38 // |
|
|
39 //####DESCRIPTIONEND#### |
|
|
40 // |
|
|
41 //========================================================================== |
|
|
42 |
|
|
43 #include <pkgconf/kernel.h> |
|
|
44 |
|
|
45 #include <cyg/kernel/ktypes.h> // base kernel types |
|
|
46 #include <cyg/infra/cyg_trac.h> // tracing macros |
|
|
47 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
48 #include <cyg/kernel/instrmnt.h> // instrumentation |
|
|
49 |
|
|
50 #include <cyg/kernel/thread.inl> // Cyg_Thread inlines |
|
|
51 |
|
|
52 #include <cyg/kernel/sema2.hxx> // our header |
|
|
53 |
|
|
54 #include <cyg/kernel/sched.inl> // scheduler inlines |
|
|
55 |
|
|
56 // ------------------------------------------------------------------------- |
|
|
57 // Constructor |
|
|
58 |
|
|
59 Cyg_Counting_Semaphore2::Cyg_Counting_Semaphore2( |
|
|
60 cyg_count32 init_count // Initial count value |
|
|
61 ) |
|
|
62 { |
|
|
63 count = init_count; |
|
|
64 } |
|
|
65 |
|
|
66 // ------------------------------------------------------------------------- |
|
|
67 // Destructor |
|
|
68 |
|
|
69 Cyg_Counting_Semaphore2::~Cyg_Counting_Semaphore2() |
|
|
70 { |
|
|
71 CYG_REPORT_FUNCTION(); |
|
|
72 #if 0 |
|
|
73 CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads"); |
|
|
74 #endif |
|
|
75 // Prevent preemption |
|
|
76 Cyg_Scheduler::lock(); |
|
|
77 |
|
|
78 while ( ! queue.empty() ) { |
|
|
79 Cyg_Thread *thread = queue.dequeue(); |
|
|
80 thread->set_wake_reason( Cyg_Thread::DESTRUCT ); |
|
|
81 thread->wake(); |
|
|
82 } |
|
|
83 |
|
|
84 // Unlock the scheduler and maybe switch threads |
|
|
85 Cyg_Scheduler::unlock(); |
|
|
86 CYG_REPORT_RETURN(); |
|
|
87 } |
|
|
88 |
|
|
89 // ------------------------------------------------------------------------- |
|
|
90 // Wait until the count can be decremented without it becoming |
|
|
91 // negative. |
|
|
92 |
|
|
93 cyg_bool Cyg_Counting_Semaphore2::wait() |
|
|
94 { |
|
|
95 CYG_REPORT_FUNCTION(); |
|
|
96 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
97 cyg_bool result = true; |
|
|
98 |
|
|
99 // Prevent preemption |
|
|
100 Cyg_Scheduler::lock(); |
|
|
101 |
|
|
102 CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
|
103 |
|
|
104 if ( 0 < count ) { |
|
|
105 count--; |
|
|
106 Cyg_Scheduler::unlock(); |
|
|
107 } |
|
|
108 else { |
|
|
109 self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
|
110 self->sleep(); |
|
|
111 queue.enqueue( self ); |
|
|
112 |
|
|
113 CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
|
114 |
|
|
115 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, |
|
|
116 "Called with non-zero scheduler lock"); |
|
|
117 |
|
|
118 Cyg_Scheduler::unlock(); |
|
|
119 |
|
|
120 CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
|
121 |
|
|
122 switch( self->get_wake_reason() ) |
|
|
123 { |
|
|
124 case Cyg_Thread::DESTRUCT: |
|
|
125 case Cyg_Thread::BREAK: |
|
|
126 result = false; |
|
|
127 break; |
|
|
128 |
|
|
129 case Cyg_Thread::EXIT: |
|
|
130 self->exit(); |
|
|
131 break; |
|
|
132 |
|
|
133 default: |
|
|
134 break; |
|
|
135 } |
|
|
136 } |
|
|
137 |
|
|
138 CYG_REPORT_RETVAL( result ); |
|
|
139 return result; |
|
|
140 } |
|
|
141 |
|
|
142 // ------------------------------------------------------------------------- |
|
|
143 // Wait until the count can be decremented without it becoming |
|
|
144 // negative. |
|
|
145 |
|
|
146 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
147 |
|
|
148 cyg_bool |
|
|
149 Cyg_Counting_Semaphore2::wait( cyg_tick_count abs_timeout ) |
|
|
150 { |
|
|
151 CYG_REPORT_FUNCTION(); |
|
|
152 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
153 cyg_bool result = true; |
|
|
154 |
|
|
155 // Prevent preemption |
|
|
156 Cyg_Scheduler::lock(); |
|
|
157 |
|
|
158 CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
|
159 |
|
|
160 if ( 0 < count ) { |
|
|
161 count--; |
|
|
162 Cyg_Scheduler::unlock(); |
|
|
163 } |
|
|
164 else { |
|
|
165 |
|
|
166 // Put thread in sleep state before setting timer since if the |
|
|
167 // timeout is in the past, it will be re-awoken |
|
|
168 // immediately. If this happens then wake_reason will not be |
|
|
169 // NONE. |
|
|
170 |
|
|
171 self->sleep(); |
|
|
172 |
|
|
173 self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); |
|
|
174 |
|
|
175 // only enqueue if the timeout did not already happen |
|
|
176 if( Cyg_Thread::NONE == self->get_wake_reason() ) |
|
|
177 queue.enqueue( self ); |
|
|
178 |
|
|
179 CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
|
180 |
|
|
181 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, |
|
|
182 "Called with non-zero scheduler lock"); |
|
|
183 |
|
|
184 Cyg_Scheduler::unlock(); |
|
|
185 |
|
|
186 // Clear the timeout. It is irrelevant whether the alarm has |
|
|
187 // actually gone off or not. |
|
|
188 self->clear_timer(); |
|
|
189 |
|
|
190 CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
|
191 |
|
|
192 switch( self->get_wake_reason() ) |
|
|
193 { |
|
|
194 case Cyg_Thread::TIMEOUT: |
|
|
195 result = false; |
|
|
196 CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count); |
|
|
197 break; |
|
|
198 |
|
|
199 case Cyg_Thread::DESTRUCT: |
|
|
200 case Cyg_Thread::BREAK: |
|
|
201 result = false; |
|
|
202 break; |
|
|
203 |
|
|
204 case Cyg_Thread::EXIT: |
|
|
205 self->exit(); |
|
|
206 break; |
|
|
207 |
|
|
208 default: |
|
|
209 break; |
|
|
210 } |
|
|
211 } |
|
|
212 |
|
|
213 CYG_REPORT_RETVAL( result ); |
|
|
214 return result; |
|
|
215 } |
|
|
216 |
|
|
217 #endif // CYGFUN_KERNEL_THREADS_TIMER |
|
|
218 |
|
|
219 // ------------------------------------------------------------------------- |
|
|
220 // Try to decrement, but fail if not possible |
|
|
221 |
|
|
222 cyg_bool Cyg_Counting_Semaphore2::trywait() |
|
|
223 { |
|
|
224 CYG_REPORT_FUNCTION(); |
|
|
225 cyg_bool result = true; |
|
|
226 |
|
|
227 // Prevent preemption |
|
|
228 Cyg_Scheduler::lock(); |
|
|
229 |
|
|
230 if( 0 < count ) count--; |
|
|
231 else result = false; |
|
|
232 |
|
|
233 CYG_INSTRUMENT_CNTSEM( TRY, this, result ); |
|
|
234 |
|
|
235 // Unlock the scheduler and maybe switch threads |
|
|
236 Cyg_Scheduler::unlock(); |
|
|
237 |
|
|
238 CYG_REPORT_RETVAL( result ); |
|
|
239 return result; |
|
|
240 } |
|
|
241 |
|
|
242 // ------------------------------------------------------------------------- |
|
|
243 // Increment count |
|
|
244 |
|
|
245 void Cyg_Counting_Semaphore2::post() |
|
|
246 { |
|
|
247 CYG_REPORT_FUNCTION(); |
|
|
248 // Prevent preemption |
|
|
249 Cyg_Scheduler::lock(); |
|
|
250 |
|
|
251 CYG_INSTRUMENT_CNTSEM( POST, this, 0 ); |
|
|
252 |
|
|
253 if( queue.empty() ) { |
|
|
254 count++; |
|
|
255 } |
|
|
256 else { |
|
|
257 // The queue is non-empty, so grab the next |
|
|
258 // thread from it and wake it up. The waiter |
|
|
259 // won't decrement the count when he is awakened, |
|
|
260 // for we never incremented it in the first place |
|
|
261 |
|
|
262 Cyg_Thread *thread = queue.dequeue(); |
|
|
263 |
|
|
264 thread->set_wake_reason( Cyg_Thread::DONE ); |
|
|
265 |
|
|
266 thread->wake(); |
|
|
267 |
|
|
268 CYG_INSTRUMENT_CNTSEM( WAKE, this, thread ); |
|
|
269 } |
|
|
270 |
|
|
271 // Unlock the scheduler and maybe switch threads |
|
|
272 Cyg_Scheduler::unlock(); |
|
|
273 CYG_REPORT_RETURN(); |
|
|
274 } |
|
|
275 |
|
|
276 // ------------------------------------------------------------------------- |
|
|
277 // Get current count value |
|
|
278 |
|
|
279 cyg_count32 Cyg_Counting_Semaphore2::peek() |
|
|
280 { |
|
|
281 // This is a single read of the value of count. |
|
|
282 // This is already atomic, hence there is no need |
|
|
283 // to lock the scheduler. |
|
|
284 |
|
|
285 return count; |
|
|
286 } |
|
|
287 |
|
|
288 // ------------------------------------------------------------------------- |
|
|
289 // EOF sync/cnt_sem2.cxx |