comparison packages/kernel/current/src/sync/mutex.cxx @ 2:443894e2e912 ecos-v1_2_1-release

Block commit of eCos version 1.2.1
author jlarmour
date Tue, 11 May 1999 12:24:34 +0000
parents 3111d98ba7b3
children 18ee5a9c102e
comparison
equal deleted inserted replaced
1:72f549f0d891 2:443894e2e912
1 //========================================================================== 1 //==========================================================================
2 // 2 //
3 // sync/mutex.cxx 3 // sync/mutex.cxx
4 // 4 //
5 // Mutex and condition variable implementation 5 // Mutex and condition variable implementation
6 // 6 //
7 //========================================================================== 7 //==========================================================================
8 //####COPYRIGHTBEGIN#### 8 //####COPYRIGHTBEGIN####
9 // 9 //
10 // ------------------------------------------- 10 // -------------------------------------------
20 // 20 //
21 // The Original Code is eCos - Embedded Cygnus Operating System, released 21 // The Original Code is eCos - Embedded Cygnus Operating System, released
22 // September 30, 1998. 22 // September 30, 1998.
23 // 23 //
24 // The Initial Developer of the Original Code is Cygnus. Portions created 24 // The Initial Developer of the Original Code is Cygnus. Portions created
25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. 25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved.
26 // ------------------------------------------- 26 // -------------------------------------------
27 // 27 //
28 //####COPYRIGHTEND#### 28 //####COPYRIGHTEND####
29 //========================================================================== 29 //==========================================================================
30 //#####DESCRIPTIONBEGIN#### 30 //#####DESCRIPTIONBEGIN####
31 // 31 //
32 // Author(s): nickg 32 // Author(s): nickg
33 // Contributors: nickg 33 // Contributors: nickg, jlarmour
34 // Date: 1997-10-21 34 // Date: 1999-02-17
35 // Purpose: Mutex implementation 35 // Purpose: Mutex implementation
36 // Description: This file contains the implementations of the mutex 36 // Description: This file contains the implementations of the mutex
37 // and condition variable classes. 37 // and condition variable classes.
38 // 38 //
39 //####DESCRIPTIONEND#### 39 //####DESCRIPTIONEND####
40 // 40 //
41 //========================================================================== 41 //==========================================================================
42 42
61 { 61 {
62 CYG_REPORT_FUNCTION(); 62 CYG_REPORT_FUNCTION();
63 63
64 locked = false; 64 locked = false;
65 owner = NULL; 65 owner = NULL;
66
67 CYG_REPORT_RETURN();
66 } 68 }
67 69
68 // ------------------------------------------------------------------------- 70 // -------------------------------------------------------------------------
69 // Destructor 71 // Destructor
70 72
72 { 74 {
73 CYG_REPORT_FUNCTION(); 75 CYG_REPORT_FUNCTION();
74 76
75 CYG_ASSERT( owner == NULL, "Deleting mutex with owner"); 77 CYG_ASSERT( owner == NULL, "Deleting mutex with owner");
76 CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads"); 78 CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads");
79 CYG_REPORT_RETURN();
77 } 80 }
78 81
79 // ------------------------------------------------------------------------- 82 // -------------------------------------------------------------------------
80 83
81 #ifdef CYGDBG_USE_ASSERTS 84 #ifdef CYGDBG_USE_ASSERTS
82 85
83 bool Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) 86 bool
87 Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const
84 { 88 {
85 // CYG_REPORT_FUNCTION(); 89 // CYG_REPORT_FUNCTION();
86 90
87 // check that we have a non-NULL pointer first 91 // check that we have a non-NULL pointer first
88 if( this == NULL ) return false; 92 if( this == NULL ) return false;
107 #endif 111 #endif
108 112
109 // ------------------------------------------------------------------------- 113 // -------------------------------------------------------------------------
110 // Lock and/or wait 114 // Lock and/or wait
111 115
112 cyg_bool Cyg_Mutex::lock() 116 cyg_bool
113 { 117 Cyg_Mutex::lock(void)
114 CYG_REPORT_FUNCTION(); 118 {
119 CYG_REPORT_FUNCTYPE("returning %d");
115 120
116 cyg_bool result = true; 121 cyg_bool result = true;
117 Cyg_Thread *self = Cyg_Thread::self(); 122 Cyg_Thread *self = Cyg_Thread::self();
118 123
119 // Prevent preemption 124 // Prevent preemption
126 // Loop while the mutex is locked, sleeping each time around 131 // Loop while the mutex is locked, sleeping each time around
127 // the loop. This copes with the possibility of a higher priority 132 // the loop. This copes with the possibility of a higher priority
128 // thread grabbing the mutex between the wakeup in unlock() and 133 // thread grabbing the mutex between the wakeup in unlock() and
129 // this thread actually starting. 134 // this thread actually starting.
130 135
131 while( locked ) 136 while( locked && result )
132 { 137 {
133 CYG_ASSERT( self != owner, "Locking mutex I already own"); 138 CYG_ASSERT( self != owner, "Locking mutex I already own");
134 139
135 self->set_sleep_reason( Cyg_Thread::WAIT ); 140 self->set_sleep_reason( Cyg_Thread::WAIT );
136 141
189 // Unlock the scheduler and maybe switch threads 194 // Unlock the scheduler and maybe switch threads
190 Cyg_Scheduler::unlock(); 195 Cyg_Scheduler::unlock();
191 196
192 CYG_ASSERTCLASS( this, "Bad this pointer"); 197 CYG_ASSERTCLASS( this, "Bad this pointer");
193 198
199 CYG_REPORT_RETVAL(result);
200
194 return result; 201 return result;
195 } 202 }
196 203
197 // ------------------------------------------------------------------------- 204 // -------------------------------------------------------------------------
198 // Try to lock and return success 205 // Try to lock and return success
199 206
200 cyg_bool Cyg_Mutex::trylock() 207 cyg_bool
201 { 208 Cyg_Mutex::trylock(void)
202 CYG_REPORT_FUNCTION(); 209 {
210 CYG_REPORT_FUNCTYPE("returning %d");
203 211
204 CYG_ASSERTCLASS( this, "Bad this pointer"); 212 CYG_ASSERTCLASS( this, "Bad this pointer");
205 213
206 cyg_bool result = true; 214 cyg_bool result = true;
207 215
228 CYG_INSTRUMENT_MUTEX(TRY, this, result); 236 CYG_INSTRUMENT_MUTEX(TRY, this, result);
229 237
230 // Unlock the scheduler and maybe switch threads 238 // Unlock the scheduler and maybe switch threads
231 Cyg_Scheduler::unlock(); 239 Cyg_Scheduler::unlock();
232 240
241 CYG_REPORT_RETVAL(result);
233 return result; 242 return result;
234 } 243 }
235 244
236 // ------------------------------------------------------------------------- 245 // -------------------------------------------------------------------------
237 // unlock 246 // unlock
238 247
239 void Cyg_Mutex::unlock() 248 void
249 Cyg_Mutex::unlock(void)
240 { 250 {
241 CYG_REPORT_FUNCTION(); 251 CYG_REPORT_FUNCTION();
242 252
243 // Prevent preemption 253 // Prevent preemption
244 Cyg_Scheduler::lock(); 254 Cyg_Scheduler::lock();
279 CYG_ASSERTCLASS( this, "Bad this pointer"); 289 CYG_ASSERTCLASS( this, "Bad this pointer");
280 290
281 // Unlock the scheduler and maybe switch threads 291 // Unlock the scheduler and maybe switch threads
282 Cyg_Scheduler::unlock(); 292 Cyg_Scheduler::unlock();
283 293
294 CYG_REPORT_RETURN();
295 }
296
297 // -------------------------------------------------------------------------
298 // Release all waiting threads.
299
300 void Cyg_Mutex::release()
301 {
302 CYG_REPORT_FUNCTION();
303
304 // Prevent preemption
305 Cyg_Scheduler::lock();
306
307 CYG_INSTRUMENT_MUTEX(RELEASE, this, 0);
308
309 CYG_ASSERTCLASS( this, "Bad this pointer");
310
311 while( !queue.empty() )
312 {
313 // The queue is non-empty, so grab each
314 // thread from it and release it.
315
316 Cyg_Thread *thread = queue.dequeue();
317
318 CYG_ASSERTCLASS( thread, "Bad thread pointer");
319
320 thread->release();
321
322 CYG_INSTRUMENT_MUTEX(RELEASED, this, thread);
323
324 }
325
326 CYG_ASSERTCLASS( this, "Bad this pointer");
327
328 // Unlock the scheduler and maybe switch threads
329 Cyg_Scheduler::unlock();
330
331 CYG_REPORT_RETURN();
284 } 332 }
285 333
286 //========================================================================== 334 //==========================================================================
287 // Condition variables 335 // Condition variables
288 336
293 CYG_REPORT_FUNCTION(); 341 CYG_REPORT_FUNCTION();
294 342
295 mutex = &mx; 343 mutex = &mx;
296 344
297 CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); 345 CYG_ASSERTCLASS( mutex, "Invalid mutex argument");
346
347 CYG_REPORT_RETURN();
298 } 348 }
299 349
300 // ------------------------------------------------------------------------- 350 // -------------------------------------------------------------------------
301 // Destructor 351 // Destructor
302 352
303 Cyg_Condition_Variable::~Cyg_Condition_Variable() 353 Cyg_Condition_Variable::~Cyg_Condition_Variable()
304 { 354 {
305 CYG_REPORT_FUNCTION(); 355 CYG_REPORT_FUNCTION();
306 356
307 CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads"); 357 CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads");
358
359 CYG_REPORT_RETURN();
308 } 360 }
309 361
310 // ------------------------------------------------------------------------- 362 // -------------------------------------------------------------------------
311 363
312 #ifdef CYGDBG_USE_ASSERTS 364 #ifdef CYGDBG_USE_ASSERTS
313 365
314 bool Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) 366 bool
315 { 367 Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const
316 CYG_REPORT_FUNCTION(); 368 {
369 bool result = true;
370
371 CYG_REPORT_FUNCTYPE("returning %d");
372 CYG_REPORT_FUNCARG1("zeal = %d", zeal);
317 373
318 // check that we have a non-NULL pointer first 374 // check that we have a non-NULL pointer first
319 if( this == NULL ) return false; 375 if( this == NULL )
320 376 result = false;
321 switch( zeal ) 377 else {
322 { 378
323 case cyg_system_test: 379 switch( zeal )
324 case cyg_extreme: 380 {
325 case cyg_thorough: 381 case cyg_system_test:
326 if( !mutex->check_this(zeal) ) return false; 382 case cyg_extreme:
327 case cyg_quick: 383 case cyg_thorough:
328 case cyg_trivial: 384 if( !mutex->check_this(zeal) )
329 case cyg_none: 385 result = false;
330 default: 386 case cyg_quick:
331 break; 387 case cyg_trivial:
332 }; 388 case cyg_none:
333 389 default:
334 return true; 390 break;
391 }
392 }
393
394 CYG_REPORT_RETVAL(result);
395 return result;
335 } 396 }
336 397
337 #endif 398 #endif
338 399
339 // ------------------------------------------------------------------------- 400 // -------------------------------------------------------------------------
340 // Wait for condition to be true 401 // Wait for condition to be true
341 402 // Note: if this function is entered with the scheduler locked (e.g. to
342 void Cyg_Condition_Variable::wait() 403 // suspend DSR processing) then there is no need to take the lock. Also
404 // in this case, exit with the scheduler locked, which allows this function
405 // to be used in a totally thread-safe manner.
406
407 void
408 Cyg_Condition_Variable::wait(void)
343 { 409 {
344 CYG_REPORT_FUNCTION(); 410 CYG_REPORT_FUNCTION();
345 411
346 Cyg_Thread *self = Cyg_Thread::self(); 412 Cyg_Thread *self = Cyg_Thread::self();
347 413
348 // Prevent preemption 414 cyg_int32 current_lock = Cyg_Scheduler::get_sched_lock();
349 Cyg_Scheduler::lock(); 415
416 if (current_lock == 0)
417 // Prevent preemption
418 Cyg_Scheduler::lock();
350 419
351 CYG_ASSERTCLASS( this, "Bad this pointer"); 420 CYG_ASSERTCLASS( this, "Bad this pointer");
352 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 421 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
353 CYG_ASSERTCLASS( self, "Bad self thread"); 422 CYG_ASSERTCLASS( self, "Bad self thread");
354 423
386 // When we awake, we must re-acquire the mutex. Note that while 455 // When we awake, we must re-acquire the mutex. Note that while
387 // it is essential to release the mutex and queue on the CV 456 // it is essential to release the mutex and queue on the CV
388 // atomically relative to other threads, to avoid races, it is not 457 // atomically relative to other threads, to avoid races, it is not
389 // necessary for us to re-acquire the mutex in the same atomic 458 // necessary for us to re-acquire the mutex in the same atomic
390 // action. Hence we can do it after unlocking the scheduler. 459 // action. Hence we can do it after unlocking the scheduler.
391 460 // We need to loop here in case the thread is released while waiting
392 mutex->lock(); 461 // for the mutex. It is essential that we exit this function with the
462 // mutex claimed.
463
464 while ( !mutex->lock() )
465 continue;
393 466
394 CYG_ASSERTCLASS( this, "Bad this pointer"); 467 CYG_ASSERTCLASS( this, "Bad this pointer");
395 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 468 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
396 CYG_ASSERT( mutex->owner == self, "Not mutex owner"); 469 CYG_ASSERT( mutex->owner == self, "Not mutex owner");
470
471 CYG_REPORT_RETURN();
472
473 if (current_lock)
474 // Reacquire the DSR pseudo lock
475 Cyg_Scheduler::lock();
397 } 476 }
398 477
399 // ------------------------------------------------------------------------- 478 // -------------------------------------------------------------------------
400 // Wake one thread 479 // Wake one thread
401 480
402 void Cyg_Condition_Variable::signal() 481 void
482 Cyg_Condition_Variable::signal(void)
403 { 483 {
404 CYG_REPORT_FUNCTION(); 484 CYG_REPORT_FUNCTION();
405 485
406 CYG_ASSERTCLASS( this, "Bad this pointer"); 486 CYG_ASSERTCLASS( this, "Bad this pointer");
407 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 487 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
432 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 512 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
433 513
434 // Unlock the scheduler and maybe switch threads 514 // Unlock the scheduler and maybe switch threads
435 Cyg_Scheduler::unlock(); 515 Cyg_Scheduler::unlock();
436 516
517 CYG_REPORT_RETURN();
437 } 518 }
438 519
439 // ------------------------------------------------------------------------- 520 // -------------------------------------------------------------------------
440 // Set cond true, wake all threads 521 // Set cond true, wake all threads
441 522
442 void Cyg_Condition_Variable::broadcast() 523 void
524 Cyg_Condition_Variable::broadcast(void)
443 { 525 {
444 CYG_REPORT_FUNCTION(); 526 CYG_REPORT_FUNCTION();
445 527
446 CYG_ASSERTCLASS( this, "Bad this pointer"); 528 CYG_ASSERTCLASS( this, "Bad this pointer");
447 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 529 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
470 CYG_ASSERTCLASS( this, "Bad this pointer"); 552 CYG_ASSERTCLASS( this, "Bad this pointer");
471 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 553 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
472 554
473 // Unlock the scheduler and maybe switch threads 555 // Unlock the scheduler and maybe switch threads
474 Cyg_Scheduler::unlock(); 556 Cyg_Scheduler::unlock();
557
558 CYG_REPORT_RETURN();
475 } 559 }
476 560
477 // ------------------------------------------------------------------------- 561 // -------------------------------------------------------------------------
478 // Optional timed wait on a CV 562 // Optional timed wait on a CV
479 563
480 #if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) && defined(CYGFUN_KERNEL_THREADS_TIMER) 564 #if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT)
481 565
482 cyg_bool Cyg_Condition_Variable::wait( cyg_tick_count timeout ) 566 cyg_bool
483 { 567 Cyg_Condition_Variable::wait( cyg_tick_count timeout )
484 CYG_REPORT_FUNCTION(); 568 {
569 CYG_REPORT_FUNCTYPE("returning %d");
570 CYG_REPORT_FUNCARG1("timeout = %d", timeout);
485 571
486 CYG_ASSERTCLASS( this, "Bad this pointer"); 572 CYG_ASSERTCLASS( this, "Bad this pointer");
487 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 573 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
488 574
489 cyg_bool result = true; 575 cyg_bool result = true;
545 // it is essential to release the mutex and queue on the CV 631 // it is essential to release the mutex and queue on the CV
546 // atomically relative to other threads, to avoid races, it is not 632 // atomically relative to other threads, to avoid races, it is not
547 // necessary for us to re-acquire the mutex in the same atomic 633 // necessary for us to re-acquire the mutex in the same atomic
548 // action. Hence we can do it after unlocking the scheduler. 634 // action. Hence we can do it after unlocking the scheduler.
549 635
550 mutex->lock(); 636 // FIXME: what if we woke up above due to TIMEOUT/DESTRUCT/BREAK?
551 637 // In that situation is it correct to not lock the mutex?
552 CYG_ASSERTCLASS( this, "Bad this pointer"); 638 if (false != result)
553 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); 639 result = mutex->lock();
640
641 CYG_ASSERTCLASS( this, "Bad this pointer");
642 CYG_ASSERTCLASS( mutex, "Corrupt mutex");
643
644 CYG_REPORT_RETVAL(result);
554 645
555 return result; 646 return result;
556 } 647 }
557 648
558 #endif 649 #endif