Mercurial > ecos
comparison packages/kernel/current/src/sync/mutex.cxx @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | 59d97b6ba612 |
| children | 0ec04793409a |
comparison
equal
deleted
inserted
replaced
| 114:5ad2b71d525e | 115:6ed91473a1cd |
|---|---|
| 53 | 53 |
| 54 #include <cyg/kernel/thread.inl> // thread inlines | 54 #include <cyg/kernel/thread.inl> // thread inlines |
| 55 #include <cyg/kernel/sched.inl> // scheduler inlines | 55 #include <cyg/kernel/sched.inl> // scheduler inlines |
| 56 #include <cyg/kernel/clock.inl> // clock inlines | 56 #include <cyg/kernel/clock.inl> // clock inlines |
| 57 | 57 |
| 58 // ------------------------------------------------------------------------- | |
| 59 // Mutex protocol test macros. | |
| 60 // If the dynamic protocol option is enabled, then these generate appropriate | |
| 61 // tests on the protocol field. If there is no dynamic choice then they simply | |
| 62 // result in empty statements. | |
| 63 | |
| 64 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC | |
| 65 | |
| 66 #define IF_PROTOCOL_INHERIT if( protocol == INHERIT ) | |
| 67 #define IF_PROTOCOL_CEILING if( protocol == CEILING ) | |
| 68 | |
| 69 #else | |
| 70 | |
| 71 #define IF_PROTOCOL_INHERIT | |
| 72 #define IF_PROTOCOL_CEILING | |
| 73 | |
| 74 #endif | |
| 58 | 75 |
| 59 // ------------------------------------------------------------------------- | 76 // ------------------------------------------------------------------------- |
| 60 // Constructor | 77 // Constructor |
| 61 | 78 |
| 62 Cyg_Mutex::Cyg_Mutex() | 79 Cyg_Mutex::Cyg_Mutex() |
| 64 CYG_REPORT_FUNCTION(); | 81 CYG_REPORT_FUNCTION(); |
| 65 | 82 |
| 66 locked = false; | 83 locked = false; |
| 67 owner = NULL; | 84 owner = NULL; |
| 68 | 85 |
| 69 CYG_REPORT_RETURN(); | 86 #if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT) && \ |
| 70 } | 87 defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) |
| 88 | |
| 89 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT | |
| 90 protocol = INHERIT; | |
| 91 #endif | |
| 92 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING | |
| 93 protocol = CEILING; | |
| 94 ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY; | |
| 95 #endif | |
| 96 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_NONE | |
| 97 protocol = NONE; | |
| 98 #endif | |
| 99 | |
| 100 #endif | |
| 101 | |
| 102 CYG_REPORT_RETURN(); | |
| 103 } | |
| 104 | |
| 105 // ------------------------------------------------------------------------- | |
| 106 // Construct with defined protocol | |
| 107 | |
| 108 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC | |
| 109 | |
| 110 Cyg_Mutex::Cyg_Mutex( cyg_protcol protocol_arg ) | |
| 111 { | |
| 112 CYG_REPORT_FUNCTION(); | |
| 113 | |
| 114 locked = false; | |
| 115 owner = NULL; | |
| 116 | |
| 117 protocol = protocol_arg; | |
| 118 | |
| 119 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING | |
| 120 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY | |
| 121 | |
| 122 // if there is a default priority ceiling defined, use that to initialize | |
| 123 // the ceiling. | |
| 124 ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY; | |
| 125 | |
| 126 #else | |
| 127 | |
| 128 // Otherwise set it to zero. | |
| 129 ceiling = 0; | |
| 130 | |
| 131 #endif | |
| 132 #endif | |
| 133 | |
| 134 CYG_REPORT_RETURN(); | |
| 135 } | |
| 136 | |
| 137 #endif | |
| 71 | 138 |
| 72 // ------------------------------------------------------------------------- | 139 // ------------------------------------------------------------------------- |
| 73 // Destructor | 140 // Destructor |
| 74 | 141 |
| 75 Cyg_Mutex::~Cyg_Mutex() | 142 Cyg_Mutex::~Cyg_Mutex() |
| 133 // Loop while the mutex is locked, sleeping each time around | 200 // Loop while the mutex is locked, sleeping each time around |
| 134 // the loop. This copes with the possibility of a higher priority | 201 // the loop. This copes with the possibility of a higher priority |
| 135 // thread grabbing the mutex between the wakeup in unlock() and | 202 // thread grabbing the mutex between the wakeup in unlock() and |
| 136 // this thread actually starting. | 203 // this thread actually starting. |
| 137 | 204 |
| 138 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 205 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
| 139 | 206 |
| 140 self->count_mutex(); | 207 self->count_mutex(); |
| 141 | 208 |
| 142 #endif | 209 #endif |
| 143 | 210 |
| 149 | 216 |
| 150 self->sleep(); | 217 self->sleep(); |
| 151 | 218 |
| 152 queue.enqueue( self ); | 219 queue.enqueue( self ); |
| 153 | 220 |
| 154 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 221 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
| 155 | 222 |
| 156 owner->inherit_priority(self); | 223 IF_PROTOCOL_INHERIT |
| 224 owner->inherit_priority(self); | |
| 157 | 225 |
| 158 #endif | 226 #endif |
| 159 | 227 |
| 160 CYG_INSTRUMENT_MUTEX(WAIT, this, 0); | 228 CYG_INSTRUMENT_MUTEX(WAIT, this, 0); |
| 161 | 229 |
| 162 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | 230 // Allow other threads to run |
| 163 | 231 Cyg_Scheduler::reschedule(); |
| 164 // Unlock scheduler and allow other threads | 232 |
| 165 // to run | |
| 166 Cyg_Scheduler::unlock(); | |
| 167 Cyg_Scheduler::lock(); | |
| 168 | |
| 169 CYG_ASSERTCLASS( this, "Bad this pointer"); | 233 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 170 | 234 |
| 171 switch( self->get_wake_reason() ) | 235 switch( self->get_wake_reason() ) |
| 172 { | 236 { |
| 173 case Cyg_Thread::DESTRUCT: | 237 case Cyg_Thread::DESTRUCT: |
| 188 if( result ) | 252 if( result ) |
| 189 { | 253 { |
| 190 locked = true; | 254 locked = true; |
| 191 owner = self; | 255 owner = self; |
| 192 | 256 |
| 257 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING | |
| 258 | |
| 259 IF_PROTOCOL_CEILING | |
| 260 self->set_priority_ceiling(ceiling); | |
| 261 | |
| 262 #endif | |
| 263 | |
| 193 CYG_INSTRUMENT_MUTEX(LOCKED, this, 0); | 264 CYG_INSTRUMENT_MUTEX(LOCKED, this, 0); |
| 194 } | 265 } |
| 195 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 266 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
| 196 else | 267 else |
| 197 { | 268 { |
| 198 self->uncount_mutex(); | 269 IF_PROTOCOL_INHERIT |
| 199 self->disinherit_priority(); | 270 { |
| 271 self->uncount_mutex(); | |
| 272 self->disinherit_priority(); | |
| 273 } | |
| 200 } | 274 } |
| 201 #endif | 275 #endif |
| 202 | 276 |
| 203 // Unlock the scheduler and maybe switch threads | 277 // Unlock the scheduler and maybe switch threads |
| 204 Cyg_Scheduler::unlock(); | 278 Cyg_Scheduler::unlock(); |
| 232 Cyg_Thread *self = Cyg_Thread::self(); | 306 Cyg_Thread *self = Cyg_Thread::self(); |
| 233 | 307 |
| 234 locked = true; | 308 locked = true; |
| 235 owner = self; | 309 owner = self; |
| 236 | 310 |
| 237 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 311 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
| 238 | 312 |
| 239 self->count_mutex(); | 313 self->count_mutex(); |
| 240 | 314 |
| 241 #endif | 315 #endif |
| 316 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING | |
| 317 | |
| 318 IF_PROTOCOL_CEILING | |
| 319 self->set_priority_ceiling(ceiling); | |
| 320 | |
| 321 #endif | |
| 322 | |
| 242 } | 323 } |
| 243 else result = false; | 324 else result = false; |
| 244 | 325 |
| 245 CYG_INSTRUMENT_MUTEX(TRY, this, result); | 326 CYG_INSTRUMENT_MUTEX(TRY, this, result); |
| 246 | 327 |
| 275 | 356 |
| 276 Cyg_Thread *thread = queue.dequeue(); | 357 Cyg_Thread *thread = queue.dequeue(); |
| 277 | 358 |
| 278 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | 359 CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
| 279 | 360 |
| 280 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 361 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
| 281 | 362 |
| 282 // Give the owner-to-be a chance to inherit from the remaining | 363 // Give the owner-to-be a chance to inherit from the remaining |
| 283 // queue or the relinquishing thread: | 364 // queue or the relinquishing thread: |
| 284 | 365 |
| 285 thread->relay_priority(owner, &queue); | 366 IF_PROTOCOL_INHERIT |
| 367 thread->relay_priority(owner, &queue); | |
| 286 | 368 |
| 287 #endif | 369 #endif |
| 288 | 370 |
| 289 thread->set_wake_reason( Cyg_Thread::DONE ); | 371 thread->set_wake_reason( Cyg_Thread::DONE ); |
| 290 | 372 |
| 292 | 374 |
| 293 CYG_INSTRUMENT_MUTEX(WAKE, this, thread); | 375 CYG_INSTRUMENT_MUTEX(WAKE, this, thread); |
| 294 | 376 |
| 295 } | 377 } |
| 296 | 378 |
| 297 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | 379 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
| 298 | 380 |
| 299 owner->uncount_mutex(); | 381 owner->uncount_mutex(); |
| 300 owner->disinherit_priority(); | 382 |
| 301 | 383 #endif |
| 384 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT | |
| 385 | |
| 386 IF_PROTOCOL_INHERIT | |
| 387 owner->disinherit_priority(); | |
| 388 | |
| 389 #endif | |
| 390 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING | |
| 391 | |
| 392 IF_PROTOCOL_CEILING | |
| 393 owner->clear_priority_ceiling(); | |
| 394 | |
| 302 #endif | 395 #endif |
| 303 | 396 |
| 304 locked = false; | 397 locked = false; |
| 305 owner = NULL; | 398 owner = NULL; |
| 306 | 399 |
| 346 // Unlock the scheduler and maybe switch threads | 439 // Unlock the scheduler and maybe switch threads |
| 347 Cyg_Scheduler::unlock(); | 440 Cyg_Scheduler::unlock(); |
| 348 | 441 |
| 349 CYG_REPORT_RETURN(); | 442 CYG_REPORT_RETURN(); |
| 350 } | 443 } |
| 444 | |
| 445 // ------------------------------------------------------------------------- | |
| 446 // Set ceiling priority for priority ceiling protocol | |
| 447 | |
| 448 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING | |
| 449 | |
| 450 void Cyg_Mutex::set_ceiling( cyg_priority priority ) | |
| 451 { | |
| 452 CYG_REPORT_FUNCTION(); | |
| 453 | |
| 454 // CYG_ASSERT( priority >= CYG_THREAD_MAX_PRIORITY, "Priority out of range"); | |
| 455 // CYG_ASSERT( priority <= CYG_THREAD_MIN_PRIORITY, "Priority out of range"); | |
| 456 | |
| 457 // Prevent preemption | |
| 458 Cyg_Scheduler::lock(); | |
| 459 | |
| 460 ceiling = priority; | |
| 461 | |
| 462 // Unlock the scheduler | |
| 463 Cyg_Scheduler::unlock(); | |
| 464 | |
| 465 CYG_REPORT_RETURN(); | |
| 466 } | |
| 467 | |
| 468 #endif | |
| 351 | 469 |
| 352 //========================================================================== | 470 //========================================================================== |
| 353 // Condition variables | 471 // Condition variables |
| 354 | 472 |
| 355 Cyg_Condition_Variable::Cyg_Condition_Variable( | 473 Cyg_Condition_Variable::Cyg_Condition_Variable( |
| 359 CYG_REPORT_FUNCTION(); | 477 CYG_REPORT_FUNCTION(); |
| 360 | 478 |
| 361 mutex = &mx; | 479 mutex = &mx; |
| 362 | 480 |
| 363 CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); | 481 CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); |
| 482 | |
| 483 CYG_REPORT_RETURN(); | |
| 484 } | |
| 485 | |
| 486 Cyg_Condition_Variable::Cyg_Condition_Variable() | |
| 487 { | |
| 488 CYG_REPORT_FUNCTION(); | |
| 489 | |
| 490 mutex = NULL; | |
| 364 | 491 |
| 365 CYG_REPORT_RETURN(); | 492 CYG_REPORT_RETURN(); |
| 366 } | 493 } |
| 367 | 494 |
| 368 // ------------------------------------------------------------------------- | 495 // ------------------------------------------------------------------------- |
| 397 switch( zeal ) | 524 switch( zeal ) |
| 398 { | 525 { |
| 399 case cyg_system_test: | 526 case cyg_system_test: |
| 400 case cyg_extreme: | 527 case cyg_extreme: |
| 401 case cyg_thorough: | 528 case cyg_thorough: |
| 402 if( !mutex->check_this(zeal) ) | 529 if( mutex != NULL && !mutex->check_this(zeal) ) |
| 403 result = false; | 530 result = false; |
| 404 case cyg_quick: | 531 case cyg_quick: |
| 405 case cyg_trivial: | 532 case cyg_trivial: |
| 406 case cyg_none: | 533 case cyg_none: |
| 407 default: | 534 default: |
| 420 // Note: if this function is entered with the scheduler locked (e.g. to | 547 // Note: if this function is entered with the scheduler locked (e.g. to |
| 421 // suspend DSR processing) then there is no need to take the lock. Also | 548 // suspend DSR processing) then there is no need to take the lock. Also |
| 422 // in this case, exit with the scheduler locked, which allows this function | 549 // in this case, exit with the scheduler locked, which allows this function |
| 423 // to be used in a totally thread-safe manner. | 550 // to be used in a totally thread-safe manner. |
| 424 | 551 |
| 425 void | 552 cyg_bool |
| 426 Cyg_Condition_Variable::wait(void) | 553 Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx ) |
| 427 { | 554 { |
| 428 CYG_REPORT_FUNCTION(); | 555 CYG_REPORT_FUNCTION(); |
| 429 | 556 |
| 557 cyg_bool result = true; | |
| 430 Cyg_Thread *self = Cyg_Thread::self(); | 558 Cyg_Thread *self = Cyg_Thread::self(); |
| 431 | 559 |
| 432 cyg_int32 current_lock = Cyg_Scheduler::get_sched_lock(); | 560 cyg_int32 current_lock = Cyg_Scheduler::get_sched_lock(); |
| 433 | 561 |
| 434 if (current_lock == 0) | 562 if (current_lock == 0) |
| 435 // Prevent preemption | 563 // Prevent preemption |
| 436 Cyg_Scheduler::lock(); | 564 Cyg_Scheduler::lock(); |
| 437 | 565 |
| 438 CYG_ASSERTCLASS( this, "Bad this pointer"); | 566 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 439 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | 567 CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
| 440 CYG_ASSERTCLASS( self, "Bad self thread"); | 568 CYG_ASSERTCLASS( self, "Bad self thread"); |
| 441 | 569 |
| 442 CYG_INSTRUMENT_CONDVAR(WAIT, this, 0); | 570 CYG_INSTRUMENT_CONDVAR(WAIT, this, 0); |
| 443 | 571 |
| 444 mutex->unlock(); | 572 mx->unlock(); |
| 445 | 573 |
| 446 self->set_sleep_reason( Cyg_Thread::WAIT ); | 574 self->set_sleep_reason( Cyg_Thread::WAIT ); |
| 447 | 575 |
| 448 self->sleep(); | 576 self->sleep(); |
| 449 | 577 |
| 450 queue.enqueue( self ); | 578 queue.enqueue( self ); |
| 451 | 579 |
| 452 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | 580 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); |
| 581 | |
| 582 // Avoid calling ASRs during the following unlock. | |
| 583 self->set_asr_inhibit(); | |
| 453 | 584 |
| 454 // Unlock the scheduler and switch threads | 585 // Unlock the scheduler and switch threads |
| 455 Cyg_Scheduler::unlock(); | 586 Cyg_Scheduler::unlock(); |
| 456 | 587 |
| 588 // Allow ASRs again | |
| 589 self->clear_asr_inhibit(); | |
| 590 | |
| 457 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); | 591 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); |
| 458 | 592 |
| 459 CYG_ASSERTCLASS( this, "Bad this pointer"); | 593 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 460 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | 594 CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
| 461 | 595 |
| 462 switch( self->get_wake_reason() ) | 596 switch( self->get_wake_reason() ) |
| 463 { | 597 { |
| 598 case Cyg_Thread::DESTRUCT: // which, the cv or the mutex? | |
| 599 case Cyg_Thread::BREAK: | |
| 600 result = false; | |
| 601 break; | |
| 602 | |
| 464 case Cyg_Thread::EXIT: | 603 case Cyg_Thread::EXIT: |
| 465 self->exit(); | 604 self->exit(); |
| 466 break; | 605 break; |
| 467 | 606 |
| 468 default: | 607 default: |
| 469 break; | 608 break; |
| 470 } | 609 } |
| 471 | |
| 472 | 610 |
| 473 // When we awake, we must re-acquire the mutex. Note that while | 611 // When we awake, we must re-acquire the mutex. Note that while |
| 474 // it is essential to release the mutex and queue on the CV | 612 // it is essential to release the mutex and queue on the CV |
| 475 // atomically relative to other threads, to avoid races, it is not | 613 // atomically relative to other threads, to avoid races, it is not |
| 476 // necessary for us to re-acquire the mutex in the same atomic | 614 // necessary for us to re-acquire the mutex in the same atomic |
| 477 // action. Hence we can do it after unlocking the scheduler. | 615 // action. Hence we can do it after unlocking the scheduler. |
| 478 // We need to loop here in case the thread is released while waiting | 616 // We need to loop here in case the thread is released while waiting |
| 479 // for the mutex. It is essential that we exit this function with the | 617 // for the mutex. It is essential that we exit this function with the |
| 480 // mutex claimed. | 618 // mutex claimed. |
| 481 | 619 |
| 482 while ( !mutex->lock() ) | 620 while ( !mx->lock() ) |
| 483 continue; | 621 continue; |
| 484 | 622 |
| 485 CYG_ASSERTCLASS( this, "Bad this pointer"); | 623 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 486 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | 624 CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
| 487 CYG_ASSERT( mutex->owner == self, "Not mutex owner"); | 625 CYG_ASSERT( mx->owner == self, "Not mutex owner"); |
| 488 | 626 |
| 489 CYG_REPORT_RETURN(); | 627 CYG_REPORT_RETURN(); |
| 490 | 628 |
| 491 if (current_lock) | 629 if (current_lock) |
| 492 // Reacquire the DSR pseudo lock | 630 // Reacquire the DSR pseudo lock |
| 493 Cyg_Scheduler::lock(); | 631 Cyg_Scheduler::lock(); |
| 632 | |
| 633 return result; | |
| 494 } | 634 } |
| 495 | 635 |
| 496 // ------------------------------------------------------------------------- | 636 // ------------------------------------------------------------------------- |
| 497 // Wake one thread | 637 // Wake one thread |
| 498 | 638 |
| 500 Cyg_Condition_Variable::signal(void) | 640 Cyg_Condition_Variable::signal(void) |
| 501 { | 641 { |
| 502 CYG_REPORT_FUNCTION(); | 642 CYG_REPORT_FUNCTION(); |
| 503 | 643 |
| 504 CYG_ASSERTCLASS( this, "Bad this pointer"); | 644 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 505 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 506 | 645 |
| 507 // Prevent preemption | 646 // Prevent preemption |
| 508 Cyg_Scheduler::lock(); | 647 Cyg_Scheduler::lock(); |
| 509 | 648 |
| 510 CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0); | 649 CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0); |
| 525 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); | 664 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); |
| 526 | 665 |
| 527 } | 666 } |
| 528 | 667 |
| 529 CYG_ASSERTCLASS( this, "Bad this pointer"); | 668 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 530 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 531 | 669 |
| 532 // Unlock the scheduler and maybe switch threads | 670 // Unlock the scheduler and maybe switch threads |
| 533 Cyg_Scheduler::unlock(); | 671 Cyg_Scheduler::unlock(); |
| 534 | 672 |
| 535 CYG_REPORT_RETURN(); | 673 CYG_REPORT_RETURN(); |
| 542 Cyg_Condition_Variable::broadcast(void) | 680 Cyg_Condition_Variable::broadcast(void) |
| 543 { | 681 { |
| 544 CYG_REPORT_FUNCTION(); | 682 CYG_REPORT_FUNCTION(); |
| 545 | 683 |
| 546 CYG_ASSERTCLASS( this, "Bad this pointer"); | 684 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 547 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 548 | 685 |
| 549 // Prevent preemption | 686 // Prevent preemption |
| 550 Cyg_Scheduler::lock(); | 687 Cyg_Scheduler::lock(); |
| 551 | 688 |
| 552 CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0); | 689 CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0); |
| 566 | 703 |
| 567 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); | 704 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); |
| 568 } | 705 } |
| 569 | 706 |
| 570 CYG_ASSERTCLASS( this, "Bad this pointer"); | 707 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 571 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 572 | 708 |
| 573 // Unlock the scheduler and maybe switch threads | 709 // Unlock the scheduler and maybe switch threads |
| 574 Cyg_Scheduler::unlock(); | 710 Cyg_Scheduler::unlock(); |
| 575 | 711 |
| 576 CYG_REPORT_RETURN(); | 712 CYG_REPORT_RETURN(); |
| 580 // Optional timed wait on a CV | 716 // Optional timed wait on a CV |
| 581 | 717 |
| 582 #if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) | 718 #if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) |
| 583 | 719 |
| 584 cyg_bool | 720 cyg_bool |
| 585 Cyg_Condition_Variable::wait( cyg_tick_count timeout ) | 721 Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx, cyg_tick_count timeout ) |
| 586 { | 722 { |
| 587 CYG_REPORT_FUNCTYPE("returning %d"); | 723 CYG_REPORT_FUNCTYPE("returning %d"); |
| 588 CYG_REPORT_FUNCARG1("timeout = %d", timeout); | 724 CYG_REPORT_FUNCARG1("timeout = %d", timeout); |
| 589 | 725 |
| 590 CYG_ASSERTCLASS( this, "Bad this pointer"); | 726 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 591 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | 727 CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
| 592 | 728 |
| 593 cyg_bool result = true; | 729 cyg_bool result = true; |
| 594 | 730 |
| 595 Cyg_Thread *self = Cyg_Thread::self(); | 731 Cyg_Thread *self = Cyg_Thread::self(); |
| 596 | 732 |
| 599 // Prevent preemption | 735 // Prevent preemption |
| 600 Cyg_Scheduler::lock(); | 736 Cyg_Scheduler::lock(); |
| 601 | 737 |
| 602 CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 ); | 738 CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 ); |
| 603 | 739 |
| 604 mutex->unlock(); | 740 mx->unlock(); |
| 605 | 741 |
| 606 // The ordering of sleep() and set_timer() here are | 742 // The ordering of sleep() and set_timer() here are |
| 607 // important. If the timeout is in the past, the thread | 743 // important. If the timeout is in the past, the thread |
| 608 // will be woken up immediately and will not sleep. | 744 // will be woken up immediately and will not sleep. |
| 609 | 745 |
| 615 // Only enqueue if the timeout has not already fired. | 751 // Only enqueue if the timeout has not already fired. |
| 616 if( self->get_wake_reason() == Cyg_Thread::NONE ) | 752 if( self->get_wake_reason() == Cyg_Thread::NONE ) |
| 617 queue.enqueue( self ); | 753 queue.enqueue( self ); |
| 618 | 754 |
| 619 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | 755 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); |
| 620 | 756 |
| 757 // Avoid calling ASRs during the following unlock. | |
| 758 self->set_asr_inhibit(); | |
| 759 | |
| 621 // Unlock the scheduler and switch threads | 760 // Unlock the scheduler and switch threads |
| 622 Cyg_Scheduler::unlock(); | 761 Cyg_Scheduler::unlock(); |
| 623 | 762 |
| 624 CYG_ASSERTCLASS( this, "Bad this pointer"); | 763 // Allow ASRs again |
| 625 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | 764 self->clear_asr_inhibit(); |
| 765 | |
| 766 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 767 CYG_ASSERTCLASS( mx, "Corrupt mutex"); | |
| 626 | 768 |
| 627 self->clear_timer(); | 769 self->clear_timer(); |
| 628 | 770 |
| 629 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); | 771 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); |
| 630 | 772 |
| 649 // it is essential to release the mutex and queue on the CV | 791 // it is essential to release the mutex and queue on the CV |
| 650 // atomically relative to other threads, to avoid races, it is not | 792 // atomically relative to other threads, to avoid races, it is not |
| 651 // necessary for us to re-acquire the mutex in the same atomic | 793 // necessary for us to re-acquire the mutex in the same atomic |
| 652 // action. Hence we can do it after unlocking the scheduler. | 794 // action. Hence we can do it after unlocking the scheduler. |
| 653 | 795 |
| 654 // FIXME: what if we woke up above due to TIMEOUT/DESTRUCT/BREAK? | 796 while ( !mx->lock() ) |
| 655 // In that situation is it correct to not lock the mutex? | 797 continue; |
| 656 if (false != result) | 798 |
| 657 result = mutex->lock(); | 799 CYG_ASSERTCLASS( this, "Bad this pointer"); |
| 658 | 800 CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
| 659 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 660 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 661 | 801 |
| 662 CYG_REPORT_RETVAL(result); | 802 CYG_REPORT_RETVAL(result); |
| 663 | 803 |
| 664 return result; | 804 return result; |
| 665 } | 805 } |
