Mercurial > ecos
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 |
