Mercurial > flash_v2
annotate packages/kernel/current/src/sync/mutex.cxx @ 62:7a6ac9edc838 ecos-sw-2000-01-24
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
| author | jlarmour |
|---|---|
| date | Mon, 24 Jan 2000 21:43:17 +0000 |
| parents | 18ee5a9c102e |
| children | c38311975d4f |
| rev | line source |
|---|---|
| 0 | 1 //========================================================================== |
| 2 // | |
| 2 | 3 // sync/mutex.cxx |
| 0 | 4 // |
| 2 | 5 // Mutex and condition variable 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 | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
25 // by Cygnus are Copyright (C) 1998,1999,2000 Cygnus Solutions. |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
26 // All Rights Reserved. |
| 0 | 27 // ------------------------------------------- |
| 28 // | |
| 29 //####COPYRIGHTEND#### | |
| 30 //========================================================================== | |
| 31 //#####DESCRIPTIONBEGIN#### | |
| 32 // | |
| 2 | 33 // Author(s): nickg |
| 34 // Contributors: nickg, jlarmour | |
| 35 // Date: 1999-02-17 | |
| 36 // Purpose: Mutex implementation | |
| 37 // Description: This file contains the implementations of the mutex | |
| 38 // and condition variable classes. | |
| 0 | 39 // |
| 40 //####DESCRIPTIONEND#### | |
| 41 // | |
| 42 //========================================================================== | |
| 43 | |
| 44 #include <pkgconf/kernel.h> | |
| 45 | |
| 46 #include <cyg/kernel/ktypes.h> // base kernel types | |
| 47 #include <cyg/infra/cyg_trac.h> // tracing macros | |
| 48 #include <cyg/infra/cyg_ass.h> // assertion macros | |
| 49 #include <cyg/kernel/instrmnt.h> // instrumentation | |
| 50 | |
| 51 #include <cyg/kernel/mutex.hxx> // our header | |
| 52 | |
| 53 #include <cyg/kernel/thread.inl> // thread inlines | |
| 54 #include <cyg/kernel/sched.inl> // scheduler inlines | |
| 55 #include <cyg/kernel/clock.inl> // clock inlines | |
| 56 | |
| 57 | |
| 58 // ------------------------------------------------------------------------- | |
| 59 // Constructor | |
| 60 | |
| 61 Cyg_Mutex::Cyg_Mutex() | |
| 62 { | |
| 63 CYG_REPORT_FUNCTION(); | |
| 64 | |
| 65 locked = false; | |
| 66 owner = NULL; | |
| 2 | 67 |
| 68 CYG_REPORT_RETURN(); | |
| 0 | 69 } |
| 70 | |
| 71 // ------------------------------------------------------------------------- | |
| 72 // Destructor | |
| 73 | |
| 74 Cyg_Mutex::~Cyg_Mutex() | |
| 75 { | |
| 76 CYG_REPORT_FUNCTION(); | |
| 77 | |
| 78 CYG_ASSERT( owner == NULL, "Deleting mutex with owner"); | |
| 79 CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads"); | |
| 2 | 80 CYG_REPORT_RETURN(); |
| 0 | 81 } |
| 82 | |
| 83 // ------------------------------------------------------------------------- | |
| 84 | |
| 85 #ifdef CYGDBG_USE_ASSERTS | |
| 86 | |
| 2 | 87 bool |
| 88 Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const | |
| 0 | 89 { |
| 90 // CYG_REPORT_FUNCTION(); | |
| 91 | |
| 92 // check that we have a non-NULL pointer first | |
| 93 if( this == NULL ) return false; | |
| 94 | |
| 95 switch( zeal ) | |
| 96 { | |
| 97 case cyg_system_test: | |
| 98 case cyg_extreme: | |
| 99 case cyg_thorough: | |
| 100 case cyg_quick: | |
| 101 case cyg_trivial: | |
| 102 if( locked && owner == NULL ) return false; | |
| 103 if( !locked && owner != NULL ) return false; | |
| 104 case cyg_none: | |
| 105 default: | |
| 106 break; | |
| 107 }; | |
| 108 | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 #endif | |
| 113 | |
| 114 // ------------------------------------------------------------------------- | |
| 115 // Lock and/or wait | |
| 116 | |
| 2 | 117 cyg_bool |
| 118 Cyg_Mutex::lock(void) | |
| 0 | 119 { |
| 2 | 120 CYG_REPORT_FUNCTYPE("returning %d"); |
| 0 | 121 |
| 122 cyg_bool result = true; | |
| 123 Cyg_Thread *self = Cyg_Thread::self(); | |
| 124 | |
| 125 // Prevent preemption | |
| 126 Cyg_Scheduler::lock(); | |
| 127 | |
| 128 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 129 | |
| 130 CYG_INSTRUMENT_MUTEX(LOCK, this, 0); | |
| 131 | |
| 132 // Loop while the mutex is locked, sleeping each time around | |
| 133 // the loop. This copes with the possibility of a higher priority | |
| 134 // thread grabbing the mutex between the wakeup in unlock() and | |
| 135 // this thread actually starting. | |
| 136 | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
137 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
138 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
139 self->count_mutex(); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
140 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
141 #endif |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
142 |
| 2 | 143 while( locked && result ) |
| 0 | 144 { |
| 145 CYG_ASSERT( self != owner, "Locking mutex I already own"); | |
| 146 | |
| 147 self->set_sleep_reason( Cyg_Thread::WAIT ); | |
| 148 | |
| 149 self->sleep(); | |
| 150 | |
| 151 queue.enqueue( self ); | |
| 152 | |
| 153 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | |
| 154 | |
| 155 owner->inherit_priority(self); | |
|
28
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
156 |
| 0 | 157 #endif |
| 158 | |
| 159 CYG_INSTRUMENT_MUTEX(WAIT, this, 0); | |
| 160 | |
| 161 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | |
| 162 | |
| 163 // Unlock scheduler and allow other threads | |
| 164 // to run | |
| 165 Cyg_Scheduler::unlock(); | |
| 166 Cyg_Scheduler::lock(); | |
| 167 | |
| 168 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 169 | |
| 170 switch( self->get_wake_reason() ) | |
| 171 { | |
| 172 case Cyg_Thread::DESTRUCT: | |
| 173 case Cyg_Thread::BREAK: | |
| 174 result = false; | |
| 175 break; | |
| 176 | |
| 177 case Cyg_Thread::EXIT: | |
| 178 self->exit(); | |
| 179 break; | |
| 180 | |
| 181 default: | |
| 182 break; | |
| 183 } | |
| 184 | |
| 185 } | |
| 186 | |
| 187 if( result ) | |
| 188 { | |
| 189 locked = true; | |
| 190 owner = self; | |
| 191 | |
| 192 CYG_INSTRUMENT_MUTEX(LOCKED, this, 0); | |
| 193 } | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
194 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
195 else |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
196 { |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
197 self->uncount_mutex(); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
198 self->disinherit_priority(); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
199 } |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
200 #endif |
| 0 | 201 |
| 202 // Unlock the scheduler and maybe switch threads | |
| 203 Cyg_Scheduler::unlock(); | |
| 204 | |
| 205 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 206 | |
| 2 | 207 CYG_REPORT_RETVAL(result); |
| 208 | |
| 0 | 209 return result; |
| 210 } | |
| 211 | |
| 212 // ------------------------------------------------------------------------- | |
| 213 // Try to lock and return success | |
| 214 | |
| 2 | 215 cyg_bool |
| 216 Cyg_Mutex::trylock(void) | |
| 0 | 217 { |
| 2 | 218 CYG_REPORT_FUNCTYPE("returning %d"); |
| 0 | 219 |
| 220 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 221 | |
| 222 cyg_bool result = true; | |
| 223 | |
| 224 // Prevent preemption | |
| 225 Cyg_Scheduler::lock(); | |
| 226 | |
| 227 // If the mutex is not locked, grab it | |
| 228 // for ourself. Otherwise return failure. | |
| 229 if( !locked ) | |
| 230 { | |
| 231 Cyg_Thread *self = Cyg_Thread::self(); | |
| 232 | |
| 233 locked = true; | |
| 234 owner = self; | |
| 235 | |
| 236 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE | |
| 237 | |
| 238 self->count_mutex(); | |
| 239 | |
| 240 #endif | |
| 241 } | |
| 242 else result = false; | |
| 243 | |
| 244 CYG_INSTRUMENT_MUTEX(TRY, this, result); | |
| 245 | |
| 246 // Unlock the scheduler and maybe switch threads | |
| 247 Cyg_Scheduler::unlock(); | |
| 248 | |
| 2 | 249 CYG_REPORT_RETVAL(result); |
| 0 | 250 return result; |
| 251 } | |
| 252 | |
| 253 // ------------------------------------------------------------------------- | |
| 254 // unlock | |
| 255 | |
| 2 | 256 void |
| 257 Cyg_Mutex::unlock(void) | |
| 0 | 258 { |
| 259 CYG_REPORT_FUNCTION(); | |
| 260 | |
| 261 // Prevent preemption | |
| 262 Cyg_Scheduler::lock(); | |
| 263 | |
| 264 CYG_INSTRUMENT_MUTEX(UNLOCK, this, 0); | |
| 265 | |
| 266 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 267 CYG_ASSERT( locked, "Unlock mutex that is not locked"); | |
| 268 CYG_ASSERT( owner == Cyg_Thread::self(), "Unlock mutex I do not own"); | |
| 269 | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
270 if( !queue.empty() ) { |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
271 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
272 // The queue is non-empty, so grab the next |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
273 // thread from it and wake it up. |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
274 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
275 Cyg_Thread *thread = queue.dequeue(); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
276 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
277 CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
278 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
279 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
280 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
281 // Give the owner-to-be a chance to inherit from the remaining |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
282 // queue or the relinquishing thread: |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
283 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
284 thread->relay_priority(owner, &queue); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
285 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
286 #endif |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
287 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
288 thread->set_wake_reason( Cyg_Thread::DONE ); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
289 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
290 thread->wake(); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
291 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
292 CYG_INSTRUMENT_MUTEX(WAKE, this, thread); |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
293 |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
294 } |
|
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
28
diff
changeset
|
295 |
| 0 | 296 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE |
| 297 | |
| 298 owner->uncount_mutex(); | |
| 299 owner->disinherit_priority(); | |
| 300 | |
| 301 #endif | |
| 302 | |
| 303 locked = false; | |
| 304 owner = NULL; | |
| 305 | |
| 306 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 307 | |
| 308 // Unlock the scheduler and maybe switch threads | |
| 309 Cyg_Scheduler::unlock(); | |
| 310 | |
| 2 | 311 CYG_REPORT_RETURN(); |
| 312 } | |
| 313 | |
| 314 // ------------------------------------------------------------------------- | |
| 315 // Release all waiting threads. | |
| 316 | |
| 317 void Cyg_Mutex::release() | |
| 318 { | |
| 319 CYG_REPORT_FUNCTION(); | |
| 320 | |
| 321 // Prevent preemption | |
| 322 Cyg_Scheduler::lock(); | |
| 323 | |
| 324 CYG_INSTRUMENT_MUTEX(RELEASE, this, 0); | |
| 325 | |
| 326 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 327 | |
| 328 while( !queue.empty() ) | |
| 329 { | |
| 330 // The queue is non-empty, so grab each | |
| 331 // thread from it and release it. | |
| 332 | |
| 333 Cyg_Thread *thread = queue.dequeue(); | |
| 334 | |
| 335 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | |
| 336 | |
| 337 thread->release(); | |
| 338 | |
| 339 CYG_INSTRUMENT_MUTEX(RELEASED, this, thread); | |
| 340 | |
| 341 } | |
| 342 | |
| 343 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 344 | |
| 345 // Unlock the scheduler and maybe switch threads | |
| 346 Cyg_Scheduler::unlock(); | |
| 347 | |
| 348 CYG_REPORT_RETURN(); | |
| 0 | 349 } |
| 350 | |
| 351 //========================================================================== | |
| 352 // Condition variables | |
| 353 | |
| 354 Cyg_Condition_Variable::Cyg_Condition_Variable( | |
| 355 Cyg_Mutex &mx // linked mutex | |
| 356 ) | |
| 357 { | |
| 358 CYG_REPORT_FUNCTION(); | |
| 359 | |
| 360 mutex = &mx; | |
| 361 | |
| 362 CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); | |
| 2 | 363 |
| 364 CYG_REPORT_RETURN(); | |
| 0 | 365 } |
| 366 | |
| 367 // ------------------------------------------------------------------------- | |
| 368 // Destructor | |
| 369 | |
| 370 Cyg_Condition_Variable::~Cyg_Condition_Variable() | |
| 371 { | |
| 372 CYG_REPORT_FUNCTION(); | |
| 373 | |
| 374 CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads"); | |
| 2 | 375 |
| 376 CYG_REPORT_RETURN(); | |
| 0 | 377 } |
| 378 | |
| 379 // ------------------------------------------------------------------------- | |
| 380 | |
| 381 #ifdef CYGDBG_USE_ASSERTS | |
| 382 | |
| 2 | 383 bool |
| 384 Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const | |
| 0 | 385 { |
| 2 | 386 bool result = true; |
| 387 | |
| 388 CYG_REPORT_FUNCTYPE("returning %d"); | |
| 389 CYG_REPORT_FUNCARG1("zeal = %d", zeal); | |
| 0 | 390 |
| 391 // check that we have a non-NULL pointer first | |
| 2 | 392 if( this == NULL ) |
| 393 result = false; | |
| 394 else { | |
| 395 | |
| 396 switch( zeal ) | |
| 397 { | |
| 398 case cyg_system_test: | |
| 399 case cyg_extreme: | |
| 400 case cyg_thorough: | |
| 401 if( !mutex->check_this(zeal) ) | |
| 402 result = false; | |
| 403 case cyg_quick: | |
| 404 case cyg_trivial: | |
| 405 case cyg_none: | |
| 406 default: | |
| 407 break; | |
| 408 } | |
| 409 } | |
| 0 | 410 |
| 2 | 411 CYG_REPORT_RETVAL(result); |
| 412 return result; | |
| 0 | 413 } |
| 414 | |
| 415 #endif | |
| 416 | |
| 417 // ------------------------------------------------------------------------- | |
| 418 // Wait for condition to be true | |
| 2 | 419 // Note: if this function is entered with the scheduler locked (e.g. to |
| 420 // suspend DSR processing) then there is no need to take the lock. Also | |
| 421 // in this case, exit with the scheduler locked, which allows this function | |
| 422 // to be used in a totally thread-safe manner. | |
| 0 | 423 |
| 2 | 424 void |
| 425 Cyg_Condition_Variable::wait(void) | |
| 0 | 426 { |
| 427 CYG_REPORT_FUNCTION(); | |
| 428 | |
| 429 Cyg_Thread *self = Cyg_Thread::self(); | |
| 430 | |
| 2 | 431 cyg_int32 current_lock = Cyg_Scheduler::get_sched_lock(); |
| 432 | |
| 433 if (current_lock == 0) | |
| 434 // Prevent preemption | |
| 435 Cyg_Scheduler::lock(); | |
| 0 | 436 |
| 437 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 438 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 439 CYG_ASSERTCLASS( self, "Bad self thread"); | |
| 440 | |
| 441 CYG_INSTRUMENT_CONDVAR(WAIT, this, 0); | |
| 442 | |
| 443 mutex->unlock(); | |
| 444 | |
| 445 self->set_sleep_reason( Cyg_Thread::WAIT ); | |
| 446 | |
| 447 self->sleep(); | |
| 448 | |
| 449 queue.enqueue( self ); | |
| 450 | |
| 451 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | |
| 452 | |
| 453 // Unlock the scheduler and switch threads | |
| 454 Cyg_Scheduler::unlock(); | |
| 455 | |
| 456 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); | |
| 457 | |
| 458 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 459 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 460 | |
| 461 switch( self->get_wake_reason() ) | |
| 462 { | |
| 463 case Cyg_Thread::EXIT: | |
| 464 self->exit(); | |
| 465 break; | |
| 466 | |
| 467 default: | |
| 468 break; | |
| 469 } | |
| 470 | |
| 471 | |
| 472 // When we awake, we must re-acquire the mutex. Note that while | |
| 473 // it is essential to release the mutex and queue on the CV | |
| 474 // atomically relative to other threads, to avoid races, it is not | |
| 475 // necessary for us to re-acquire the mutex in the same atomic | |
| 476 // action. Hence we can do it after unlocking the scheduler. | |
| 2 | 477 // We need to loop here in case the thread is released while waiting |
| 478 // for the mutex. It is essential that we exit this function with the | |
| 479 // mutex claimed. | |
| 480 | |
| 481 while ( !mutex->lock() ) | |
| 482 continue; | |
| 0 | 483 |
| 484 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 485 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 486 CYG_ASSERT( mutex->owner == self, "Not mutex owner"); | |
| 2 | 487 |
| 488 CYG_REPORT_RETURN(); | |
| 489 | |
| 490 if (current_lock) | |
| 491 // Reacquire the DSR pseudo lock | |
| 492 Cyg_Scheduler::lock(); | |
| 0 | 493 } |
| 494 | |
| 495 // ------------------------------------------------------------------------- | |
| 496 // Wake one thread | |
| 497 | |
| 2 | 498 void |
| 499 Cyg_Condition_Variable::signal(void) | |
| 0 | 500 { |
| 501 CYG_REPORT_FUNCTION(); | |
| 502 | |
| 503 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 504 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 505 | |
| 506 // Prevent preemption | |
| 507 Cyg_Scheduler::lock(); | |
| 508 | |
| 509 CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0); | |
| 510 | |
| 511 if( !queue.empty() ) | |
| 512 { | |
| 513 // The queue is non-empty, so grab the next | |
| 514 // thread from it and wake it up. | |
| 515 | |
| 516 Cyg_Thread *thread = queue.dequeue(); | |
| 517 | |
| 518 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | |
| 519 | |
| 520 thread->set_wake_reason( Cyg_Thread::DONE ); | |
| 521 | |
| 522 thread->wake(); | |
| 523 | |
| 524 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); | |
| 525 | |
| 526 } | |
| 527 | |
| 528 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 529 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 530 | |
| 531 // Unlock the scheduler and maybe switch threads | |
| 532 Cyg_Scheduler::unlock(); | |
| 533 | |
| 2 | 534 CYG_REPORT_RETURN(); |
| 0 | 535 } |
| 536 | |
| 537 // ------------------------------------------------------------------------- | |
| 538 // Set cond true, wake all threads | |
| 539 | |
| 2 | 540 void |
| 541 Cyg_Condition_Variable::broadcast(void) | |
| 0 | 542 { |
| 543 CYG_REPORT_FUNCTION(); | |
| 544 | |
| 545 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 546 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 547 | |
| 548 // Prevent preemption | |
| 549 Cyg_Scheduler::lock(); | |
| 550 | |
| 551 CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0); | |
| 552 | |
| 553 // Grab all the threads from the queue and let them | |
| 554 // go. | |
| 555 | |
| 556 while( !queue.empty() ) | |
| 557 { | |
| 558 Cyg_Thread *thread = queue.dequeue(); | |
| 559 | |
| 560 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | |
| 561 | |
| 562 thread->set_wake_reason( Cyg_Thread::DONE ); | |
| 563 | |
| 564 thread->wake(); | |
| 565 | |
| 566 CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); | |
| 567 } | |
| 568 | |
| 569 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 570 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 571 | |
| 572 // Unlock the scheduler and maybe switch threads | |
| 573 Cyg_Scheduler::unlock(); | |
| 2 | 574 |
| 575 CYG_REPORT_RETURN(); | |
| 0 | 576 } |
| 577 | |
| 578 // ------------------------------------------------------------------------- | |
| 579 // Optional timed wait on a CV | |
| 580 | |
| 2 | 581 #if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) |
| 0 | 582 |
| 2 | 583 cyg_bool |
| 584 Cyg_Condition_Variable::wait( cyg_tick_count timeout ) | |
| 0 | 585 { |
| 2 | 586 CYG_REPORT_FUNCTYPE("returning %d"); |
| 587 CYG_REPORT_FUNCARG1("timeout = %d", timeout); | |
| 0 | 588 |
| 589 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 590 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 591 | |
| 592 cyg_bool result = true; | |
| 593 | |
| 594 Cyg_Thread *self = Cyg_Thread::self(); | |
| 595 | |
| 596 CYG_ASSERTCLASS( self, "Bad self thread"); | |
| 597 | |
| 598 // Prevent preemption | |
| 599 Cyg_Scheduler::lock(); | |
| 600 | |
| 601 CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 ); | |
| 602 | |
| 603 mutex->unlock(); | |
| 604 | |
| 605 // The ordering of sleep() and set_timer() here are | |
| 606 // important. If the timeout is in the past, the thread | |
| 607 // will be woken up immediately and will not sleep. | |
| 608 | |
| 609 self->sleep(); | |
| 610 | |
| 611 // Set the timer and sleep reason | |
| 612 self->set_timer( timeout, Cyg_Thread::TIMEOUT ); | |
| 613 | |
| 614 // Only enqueue if the timeout has not already fired. | |
| 615 if( self->get_wake_reason() == Cyg_Thread::NONE ) | |
| 616 queue.enqueue( self ); | |
| 617 | |
| 618 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock"); | |
| 619 | |
| 620 // Unlock the scheduler and switch threads | |
| 621 Cyg_Scheduler::unlock(); | |
| 622 | |
| 623 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 624 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 625 | |
| 626 self->clear_timer(); | |
| 627 | |
| 628 CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); | |
| 629 | |
| 630 switch( self->get_wake_reason() ) | |
| 631 { | |
| 632 case Cyg_Thread::TIMEOUT: | |
| 633 case Cyg_Thread::DESTRUCT: // which, the cv or the mutex? | |
| 634 case Cyg_Thread::BREAK: | |
| 635 result = false; | |
| 636 break; | |
| 637 | |
| 638 case Cyg_Thread::EXIT: | |
| 639 self->exit(); | |
| 640 break; | |
| 641 | |
| 642 default: | |
| 643 break; | |
| 644 } | |
| 645 | |
| 646 | |
| 647 // When we awake, we must re-acquire the mutex. Note that while | |
| 648 // it is essential to release the mutex and queue on the CV | |
| 649 // atomically relative to other threads, to avoid races, it is not | |
| 650 // necessary for us to re-acquire the mutex in the same atomic | |
| 651 // action. Hence we can do it after unlocking the scheduler. | |
| 652 | |
| 2 | 653 // FIXME: what if we woke up above due to TIMEOUT/DESTRUCT/BREAK? |
| 654 // In that situation is it correct to not lock the mutex? | |
| 655 if (false != result) | |
| 656 result = mutex->lock(); | |
| 0 | 657 |
| 658 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 659 CYG_ASSERTCLASS( mutex, "Corrupt mutex"); | |
| 2 | 660 |
| 661 CYG_REPORT_RETVAL(result); | |
| 0 | 662 |
| 663 return result; | |
| 664 } | |
| 665 | |
| 666 #endif | |
| 667 | |
| 668 | |
| 669 // ------------------------------------------------------------------------- | |
| 670 // EOF sync/mutex.cxx |
