|
0
|
1 //========================================================================== |
|
|
2 // |
|
2
|
3 // flag.cxx |
|
0
|
4 // |
|
2
|
5 // Flag class 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): hmt |
|
|
33 // Contributors: hmt |
|
|
34 // Date: 1998-02-11 |
|
|
35 // Purpose: Flag implementation |
|
|
36 // Description: This file contains the implementations of the flag class |
|
0
|
37 // |
|
|
38 //####DESCRIPTIONEND#### |
|
|
39 // |
|
|
40 //========================================================================== |
|
|
41 |
|
|
42 #include <pkgconf/kernel.h> |
|
|
43 |
|
|
44 #include <cyg/kernel/ktypes.h> // base kernel types |
|
|
45 #include <cyg/infra/cyg_trac.h> // tracing macros |
|
|
46 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
47 #include <cyg/kernel/instrmnt.h> // instrumentation |
|
|
48 |
|
|
49 #include <cyg/kernel/thread.inl> // thread inlines |
|
|
50 |
|
|
51 #include <cyg/kernel/flag.hxx> // our own header |
|
|
52 |
|
|
53 #include <cyg/kernel/sched.inl> // scheduler inlines |
|
|
54 #include <cyg/kernel/clock.inl> // clock inlines |
|
|
55 |
|
|
56 // ------------------------------------------------------------------------- |
|
|
57 // Constructor |
|
|
58 |
|
|
59 Cyg_Flag::Cyg_Flag( Cyg_FlagValue init = 0 ) |
|
|
60 { |
|
|
61 CYG_REPORT_FUNCTION(); |
|
|
62 value = init; |
|
|
63 CYG_REPORT_RETURN(); |
|
|
64 } |
|
|
65 |
|
|
66 // ------------------------------------------------------------------------- |
|
|
67 // Destructor |
|
|
68 |
|
|
69 Cyg_Flag::~Cyg_Flag() |
|
|
70 { |
|
|
71 CYG_REPORT_FUNCTION(); |
|
|
72 #if 0 |
|
|
73 CYG_ASSERT( queue.empty(), "Deleting flag with threads waiting"); |
|
|
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 // debugging/assert function |
|
|
91 |
|
|
92 #ifdef CYGDBG_USE_ASSERTS |
|
|
93 cyg_bool |
|
2
|
94 Cyg_Flag::check_this(cyg_assert_class_zeal zeal) const |
|
0
|
95 { |
|
|
96 CYG_REPORT_FUNCTION(); |
|
|
97 |
|
|
98 if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() ) |
|
|
99 // then the whole thing is invalid, and we know it. |
|
|
100 // so return OK, since this check should NOT make an error. |
|
|
101 return true; |
|
|
102 |
|
|
103 // check that we have a non-NULL pointer first |
|
|
104 if( this == NULL ) { |
|
|
105 CYG_REPORT_RETVAL( false ); |
|
|
106 return false; |
|
|
107 } |
|
|
108 |
|
|
109 // there ain't a lot to check here. |
|
|
110 CYG_REPORT_RETVAL( true ); |
|
|
111 return true; |
|
|
112 } |
|
|
113 #endif |
|
|
114 |
|
|
115 // ------------------------------------------------------------------------- |
|
|
116 // now the members themselves: |
|
|
117 |
|
|
118 // clear some bits in the value (all of them by default) by ANDing with the |
|
|
119 // argument. This cannot make a wait condition become true, so there's not |
|
|
120 // much to it. |
|
|
121 void |
|
|
122 Cyg_Flag::maskbits( Cyg_FlagValue arg = 0 ) |
|
|
123 { |
|
|
124 CYG_REPORT_FUNCTION(); |
|
|
125 |
|
|
126 // Prevent preemption |
|
|
127 Cyg_Scheduler::lock(); |
|
|
128 |
|
|
129 value &= arg; |
|
|
130 // no need to wake anyone up; no waiter can become valid in |
|
|
131 // consequence of this operation. |
|
|
132 |
|
|
133 // Unlock scheduler and allow other threads to run |
|
|
134 Cyg_Scheduler::unlock(); |
|
|
135 CYG_REPORT_RETURN(); |
|
|
136 } |
|
|
137 |
|
|
138 |
|
|
139 // ------------------------------------------------------------------------- |
|
|
140 // set some bits in the value (all of them by default) and wake up any |
|
|
141 // affected waiting threads; we do the decision making here so as to get |
|
|
142 // atomicity wrt the other threads waking up - the value might have changed |
|
|
143 // by the time they get to run. |
|
|
144 |
|
|
145 void |
|
|
146 Cyg_Flag::setbits( Cyg_FlagValue arg = ~0 ) |
|
|
147 { |
|
|
148 CYG_REPORT_FUNCTION(); |
|
|
149 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
150 |
|
|
151 // Prevent preemption |
|
|
152 Cyg_Scheduler::lock(); |
|
|
153 |
|
|
154 // OR in the argument to get a new flag value. |
|
|
155 value |= arg; |
|
|
156 |
|
|
157 // anyone waiting? |
|
|
158 if ( !(queue.empty()) ) { |
|
|
159 FlagWaitInfo *p; |
|
|
160 Cyg_Thread *thread; |
|
|
161 Cyg_ThreadQueue holding; |
|
|
162 |
|
|
163 do { |
|
|
164 thread = queue.dequeue(); |
|
|
165 p = (FlagWaitInfo *)(thread->get_wait_info()); |
|
|
166 |
|
|
167 CYG_ASSERT( (p->allmask == 0) != (p->anymask == 0), |
|
|
168 "Both masks set" ); |
|
|
169 CYG_ASSERT( 0 == p->value_out, "Thread already awoken?" ); |
|
|
170 |
|
|
171 if ( ((p->allmask != 0) && (p->allmask & value) == p->allmask) || |
|
|
172 ((p->anymask & value) != 0 ) ) { |
|
|
173 // success! awaken the thread |
|
|
174 thread->set_wake_reason( Cyg_Thread::DONE ); |
|
|
175 thread->wake(); |
|
|
176 // return the successful value to it |
|
|
177 p->value_out = value; |
|
|
178 // do we clear the value; is this the end? |
|
|
179 if ( p->do_clear ) { |
|
|
180 // we can break here but need to preserve ordering |
|
|
181 value = 0; |
|
|
182 // so let it cycle the whole queue regardless |
|
|
183 } |
|
|
184 } |
|
|
185 else { |
|
|
186 // preserve the entry on the holding queue |
|
|
187 holding.enqueue( thread ); |
|
|
188 } |
|
|
189 } while ( !(queue.empty()) ); |
|
|
190 |
|
|
191 // Now re-queue the unaffected threads back into the flag queue |
|
|
192 while ( !(holding.empty()) ) { |
|
|
193 queue.enqueue( holding.dequeue() ); |
|
|
194 } |
|
|
195 } |
|
|
196 // Unlock scheduler and allow other threads to run |
|
|
197 Cyg_Scheduler::unlock(); |
|
|
198 CYG_REPORT_RETURN(); |
|
|
199 } |
|
|
200 |
|
|
201 // ------------------------------------------------------------------------- |
|
|
202 // Wait for a match on our pattern, according to the flags given. |
|
|
203 // Return the matching value. |
|
|
204 Cyg_FlagValue |
|
|
205 Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode ) |
|
|
206 { |
|
|
207 CYG_REPORT_FUNCTION(); |
|
|
208 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
209 CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
|
210 |
|
|
211 Cyg_FlagValue result; |
|
|
212 |
|
|
213 // Prevent preemption so that we compare atomically |
|
|
214 Cyg_Scheduler::lock(); |
|
|
215 |
|
|
216 // try the current value |
|
|
217 result = poll( pattern, mode ); |
|
|
218 |
|
|
219 if ( 0 != result ) { |
|
|
220 Cyg_Scheduler::unlock(); |
|
|
221 CYG_REPORT_RETVAL( result ); |
|
|
222 return result; // all done |
|
|
223 } |
|
|
224 |
|
|
225 // we have to wait until we are awoken |
|
|
226 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
227 |
|
|
228 FlagWaitInfo saveme; |
|
|
229 saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern; |
|
|
230 saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0; |
|
|
231 saveme.do_clear = (0 != (Cyg_Flag::CLR & mode)); |
|
|
232 |
|
|
233 self->set_wait_info( (CYG_ADDRWORD)&saveme ); |
|
|
234 |
|
|
235 result = true; // just being used as an early-out flag now |
|
|
236 // this loop allows us to deal correctly with spurious wakeups |
|
|
237 while ( result && (0 == saveme.value_out) ) { |
|
|
238 self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
|
239 self->sleep(); |
|
|
240 // keep track of myself on the queue of waiting threads |
|
|
241 queue.enqueue( self ); |
|
|
242 |
|
|
243 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), |
|
|
244 "Called with non-zero scheduler lock"); |
|
|
245 |
|
|
246 // Unlock scheduler and allow other threads to run |
|
|
247 Cyg_Scheduler::unlock(); |
|
|
248 Cyg_Scheduler::lock(); |
|
|
249 |
|
|
250 CYG_ASSERT( ((CYG_ADDRWORD)&saveme) == |
|
|
251 Cyg_Thread::self()->get_wait_info(), |
|
|
252 "Wait info lost" ); |
|
|
253 |
|
|
254 switch( self->get_wake_reason() ) |
|
|
255 { |
|
|
256 case Cyg_Thread::DESTRUCT: |
|
|
257 case Cyg_Thread::BREAK: |
|
|
258 result = false; |
|
|
259 break; |
|
|
260 |
|
|
261 case Cyg_Thread::EXIT: |
|
|
262 self->exit(); |
|
|
263 break; |
|
|
264 |
|
|
265 default: |
|
|
266 break; |
|
|
267 } |
|
|
268 } |
|
|
269 |
|
|
270 CYG_ASSERT( (false == result) ^ (0 != saveme.value_out), |
|
|
271 "Break out but also good result!" ); |
|
|
272 |
|
|
273 // Unlock scheduler and allow other threads to run |
|
|
274 Cyg_Scheduler::unlock(); |
|
|
275 CYG_REPORT_RETVAL( saveme.value_out ); |
|
|
276 return saveme.value_out; |
|
|
277 } |
|
|
278 |
|
|
279 // ------------------------------------------------------------------------- |
|
|
280 // Wait for a match on our pattern, with a timeout. |
|
|
281 // Return the matching value, or zero if timed out. |
|
|
282 // (zero cannot match any pattern). |
|
|
283 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
284 Cyg_FlagValue |
|
|
285 Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode, |
|
|
286 cyg_tick_count abs_timeout ) |
|
|
287 { |
|
|
288 CYG_REPORT_FUNCTION(); |
|
|
289 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
290 CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
|
291 |
|
|
292 Cyg_FlagValue result; |
|
|
293 |
|
|
294 // Prevent preemption so that we compare atomically |
|
|
295 Cyg_Scheduler::lock(); |
|
|
296 |
|
|
297 // try the current value |
|
|
298 result = poll( pattern, mode ); |
|
|
299 |
|
|
300 if ( 0 != result ) { |
|
|
301 Cyg_Scheduler::unlock(); |
|
|
302 CYG_REPORT_RETVAL( result ); |
|
|
303 return result; // all done |
|
|
304 } |
|
|
305 |
|
|
306 // we have to wait until we are awoken |
|
|
307 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
308 |
|
|
309 FlagWaitInfo saveme; |
|
|
310 saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern; |
|
|
311 saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0; |
|
|
312 saveme.do_clear = (0 != (Cyg_Flag::CLR & mode)); |
|
|
313 |
|
|
314 self->set_wait_info( (CYG_ADDRWORD)&saveme ); |
|
|
315 |
|
|
316 // Set the timer _once_ outside the loop. |
|
|
317 self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); |
|
|
318 |
|
|
319 // If the timeout was in the past, it will have changed the value |
|
|
320 // of wake_reason, so avoid going into the loop. |
|
|
321 if( self->get_wake_reason() != Cyg_Thread::NONE ) |
|
|
322 result = false; |
|
|
323 else result = true; |
|
|
324 |
|
|
325 // Result is just being used as an early-out flag now. This loop |
|
|
326 // allows us to deal correctly with spurious wakeups. |
|
|
327 |
|
|
328 while ( result && (0 == saveme.value_out) ) { |
|
|
329 self->set_sleep_reason( Cyg_Thread::TIMEOUT ); |
|
|
330 self->sleep(); |
|
|
331 // keep track of myself on the queue of waiting threads |
|
|
332 queue.enqueue( self ); |
|
|
333 |
|
|
334 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), |
|
|
335 "Called with non-zero scheduler lock"); |
|
|
336 |
|
|
337 // Unlock scheduler and allow other threads to run |
|
|
338 Cyg_Scheduler::unlock(); |
|
|
339 Cyg_Scheduler::lock(); |
|
|
340 |
|
|
341 CYG_ASSERT( ((CYG_ADDRWORD)&saveme) == |
|
|
342 Cyg_Thread::self()->get_wait_info(), |
|
|
343 "Wait info lost" ); |
|
|
344 |
|
|
345 switch( self->get_wake_reason() ) |
|
|
346 { |
|
|
347 case Cyg_Thread::TIMEOUT: |
|
|
348 result = false; |
|
|
349 break; |
|
|
350 |
|
|
351 case Cyg_Thread::DESTRUCT: |
|
|
352 case Cyg_Thread::BREAK: |
|
|
353 result = false; |
|
|
354 break; |
|
|
355 |
|
|
356 case Cyg_Thread::EXIT: |
|
|
357 self->exit(); |
|
|
358 break; |
|
|
359 |
|
|
360 default: |
|
|
361 break; |
|
|
362 } |
|
|
363 } |
|
|
364 |
|
|
365 CYG_ASSERT( (false == result) ^ (0 != saveme.value_out), |
|
|
366 "Break out but also good result!" ); |
|
|
367 |
|
|
368 // clear the timer; if it actually fired, no worries. |
|
|
369 self->clear_timer(); |
|
|
370 |
|
|
371 // Unlock scheduler and allow other threads to run |
|
|
372 Cyg_Scheduler::unlock(); |
|
|
373 // in this version, value_out might be zero meaning timed out. |
|
|
374 CYG_REPORT_RETVAL( saveme.value_out ); |
|
|
375 return saveme.value_out; |
|
|
376 } |
|
|
377 #endif // CYGFUN_KERNEL_THREADS_TIMER |
|
|
378 |
|
|
379 // ------------------------------------------------------------------------- |
|
|
380 // Test for a match on our pattern, according to the flags given. |
|
|
381 // Return the matching value if success, else zero. |
|
|
382 Cyg_FlagValue |
|
|
383 Cyg_Flag::poll( Cyg_FlagValue pattern, WaitMode mode ) |
|
|
384 { |
|
|
385 CYG_REPORT_FUNCTION(); |
|
|
386 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
387 CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
|
388 |
|
|
389 // Prevent preemption so that we compare atomically |
|
|
390 Cyg_Scheduler::lock(); |
|
|
391 |
|
|
392 Cyg_FlagValue result = 0; |
|
|
393 |
|
|
394 if ( Cyg_Flag::OR & mode ) { |
|
|
395 if ( 0 != (value & pattern) ) |
|
|
396 result = value; |
|
|
397 } |
|
|
398 else { // Cyg_Flag::AND - all must be set |
|
|
399 if ( (pattern != 0) && (pattern == (value & pattern)) ) |
|
|
400 result = value; |
|
|
401 } |
|
|
402 |
|
|
403 // result != 0 <=> test passed |
|
|
404 if ( result && (Cyg_Flag::CLR & mode) ) |
|
|
405 value = 0; |
|
|
406 |
|
|
407 Cyg_Scheduler::unlock(); |
|
|
408 |
|
|
409 CYG_REPORT_RETVAL( result ); |
|
|
410 return result; |
|
|
411 } |
|
|
412 |
|
|
413 |
|
|
414 // ------------------------------------------------------------------------- |
|
|
415 // EOF flag.cxx |