Mercurial > ecos
comparison packages/kernel/current/include/mboxt2.inl @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:3111d98ba7b3 |
|---|---|
| 1 #ifndef CYGONCE_KERNEL_MBOXT2_INL | |
| 2 #define CYGONCE_KERNEL_MBOXT2_INL | |
| 3 //========================================================================== | |
| 4 // | |
| 5 // mboxt2.inl | |
| 6 // | |
| 7 // Mboxt2 mbox template class implementation | |
| 8 // | |
| 9 //========================================================================== | |
| 10 //####COPYRIGHTBEGIN#### | |
| 11 // | |
| 12 // ------------------------------------------- | |
| 13 // The contents of this file are subject to the Cygnus eCos Public License | |
| 14 // Version 1.0 (the "License"); you may not use this file except in | |
| 15 // compliance with the License. You may obtain a copy of the License at | |
| 16 // http://sourceware.cygnus.com/ecos | |
| 17 // | |
| 18 // Software distributed under the License is distributed on an "AS IS" | |
| 19 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | |
| 20 // License for the specific language governing rights and limitations under | |
| 21 // the License. | |
| 22 // | |
| 23 // The Original Code is eCos - Embedded Cygnus Operating System, released | |
| 24 // September 30, 1998. | |
| 25 // | |
| 26 // The Initial Developer of the Original Code is Cygnus. Portions created | |
| 27 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. | |
| 28 // ------------------------------------------- | |
| 29 // | |
| 30 //####COPYRIGHTEND#### | |
| 31 //========================================================================== | |
| 32 //#####DESCRIPTIONBEGIN#### | |
| 33 // | |
| 34 // Author(s): hmt | |
| 35 // Contributors: hmt | |
| 36 // Date: 1998-02-10 | |
| 37 // Purpose: Mboxt2 template implementation | |
| 38 // Description: This file contains the implementations of the mboxt2 | |
| 39 // template classes. | |
| 40 // | |
| 41 //####DESCRIPTIONEND#### | |
| 42 // | |
| 43 //========================================================================== | |
| 44 | |
| 45 #include <cyg/kernel/ktypes.h> // base kernel types | |
| 46 #include <cyg/infra/cyg_trac.h> // tracing macros | |
| 47 #include <cyg/infra/cyg_ass.h> // assertion macros | |
| 48 #include <cyg/kernel/instrmnt.h> // instrumentation | |
| 49 | |
| 50 #include <cyg/kernel/mboxt2.hxx> // our header | |
| 51 | |
| 52 #include <cyg/kernel/thread.inl> // thread inlines | |
| 53 #include <cyg/kernel/sched.inl> // scheduler inlines | |
| 54 #include <cyg/kernel/clock.inl> // clock inlines | |
| 55 | |
| 56 // ------------------------------------------------------------------------- | |
| 57 // inline function for awakening waiting threads | |
| 58 | |
| 59 template <class T, cyg_count32 QUEUE_SIZE> | |
| 60 inline void | |
| 61 Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_winner( const T &msg ) | |
| 62 { | |
| 63 CYG_ASSERT( !get_threadq.empty(), "Where did the winner go?" ); | |
| 64 | |
| 65 // The queue is non-empty, so grab the next thread and wake it up. | |
| 66 Cyg_Thread *thread = get_threadq.dequeue(); | |
| 67 | |
| 68 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | |
| 69 | |
| 70 T *msg_ret = (T *)(thread->get_wait_info()); | |
| 71 *msg_ret = msg; | |
| 72 | |
| 73 thread->set_wake_reason( Cyg_Thread::DONE ); | |
| 74 thread->wake(); | |
| 75 | |
| 76 CYG_INSTRUMENT_MBOXT(WAKE, this, thread); | |
| 77 } | |
| 78 | |
| 79 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 80 template <class T, cyg_count32 QUEUE_SIZE> | |
| 81 inline void | |
| 82 Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_putter( void ) | |
| 83 { | |
| 84 if( !put_threadq.empty() ) { | |
| 85 // The queue is non-empty, so grab the next thread and wake it up. | |
| 86 Cyg_Thread *thread = put_threadq.dequeue(); | |
| 87 | |
| 88 CYG_ASSERTCLASS( thread, "Bad thread pointer"); | |
| 89 | |
| 90 T *new_msg = (T *)(thread->get_wait_info()); | |
| 91 | |
| 92 cyg_count32 in = base + (count++); | |
| 93 if ( size <= in ) | |
| 94 in -= size; | |
| 95 | |
| 96 CYG_ASSERT( size > in, "in overflow" ); | |
| 97 CYG_ASSERT( 0 <= in, "in overflow" ); | |
| 98 CYG_ASSERT( size >= count, "count overflow" ); | |
| 99 | |
| 100 itemqueue[ in ] = *new_msg; | |
| 101 | |
| 102 thread->set_wake_reason( Cyg_Thread::DONE ); | |
| 103 thread->wake(); | |
| 104 | |
| 105 CYG_INSTRUMENT_MBOXT(WAKE, this, thread); | |
| 106 } | |
| 107 } | |
| 108 #endif | |
| 109 | |
| 110 // ------------------------------------------------------------------------- | |
| 111 // Constructor | |
| 112 | |
| 113 template <class T, cyg_count32 QUEUE_SIZE> | |
| 114 Cyg_Mboxt2<T,QUEUE_SIZE>::Cyg_Mboxt2() | |
| 115 { | |
| 116 CYG_REPORT_FUNCTION(); | |
| 117 base = 0; | |
| 118 count = 0; | |
| 119 CYG_REPORT_RETURN(); | |
| 120 } | |
| 121 | |
| 122 // ------------------------------------------------------------------------- | |
| 123 // Destructor | |
| 124 | |
| 125 template <class T, cyg_count32 QUEUE_SIZE> | |
| 126 Cyg_Mboxt2<T,QUEUE_SIZE>::~Cyg_Mboxt2() | |
| 127 { | |
| 128 CYG_REPORT_FUNCTION(); | |
| 129 #if 0 | |
| 130 CYG_ASSERT( 0 == count, "Deleting mboxt2 with messages"); | |
| 131 CYG_ASSERT( get_threadq.empty(), "Deleting mboxt2 with threads waiting to get"); | |
| 132 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 133 CYG_ASSERT( put_threadq.empty(), "Deleting mboxt2 with threads waiting to put"); | |
| 134 #endif | |
| 135 #endif | |
| 136 // Prevent preemption | |
| 137 Cyg_Scheduler::lock(); | |
| 138 | |
| 139 while ( ! get_threadq.empty() ) { | |
| 140 Cyg_Thread *thread = get_threadq.dequeue(); | |
| 141 thread->set_wake_reason( Cyg_Thread::DESTRUCT ); | |
| 142 thread->wake(); | |
| 143 } | |
| 144 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 145 while ( ! put_threadq.empty() ) { | |
| 146 Cyg_Thread *thread = put_threadq.dequeue(); | |
| 147 thread->set_wake_reason( Cyg_Thread::DESTRUCT ); | |
| 148 thread->wake(); | |
| 149 } | |
| 150 #endif | |
| 151 | |
| 152 // Unlock the scheduler and maybe switch threads | |
| 153 Cyg_Scheduler::unlock(); | |
| 154 CYG_REPORT_RETURN(); | |
| 155 } | |
| 156 | |
| 157 // ------------------------------------------------------------------------- | |
| 158 // debugging/assert function | |
| 159 | |
| 160 #ifdef CYGDBG_USE_ASSERTS | |
| 161 | |
| 162 template <class T, cyg_count32 QUEUE_SIZE> | |
| 163 cyg_bool | |
| 164 Cyg_Mboxt2<T,QUEUE_SIZE>::check_this(cyg_assert_class_zeal zeal) | |
| 165 { | |
| 166 if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() ) | |
| 167 // then the whole thing is invalid, and we know it. | |
| 168 // so return OK, since this check should NOT make an error. | |
| 169 return true; | |
| 170 | |
| 171 // check that we have a non-NULL pointer first | |
| 172 if( this == NULL ) return false; | |
| 173 | |
| 174 #if 0 // thread queues do not have checking funcs. | |
| 175 if ( ! get_threadq.check_this( zeal ) ) return false; | |
| 176 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 177 if ( ! put_threadq.check_this( zeal ) ) return false; | |
| 178 #endif | |
| 179 #endif | |
| 180 | |
| 181 switch( zeal ) | |
| 182 { | |
| 183 case cyg_system_test: | |
| 184 case cyg_extreme: | |
| 185 case cyg_thorough: | |
| 186 case cyg_quick: | |
| 187 case cyg_trivial: | |
| 188 // plenty of scope for fencepost problems here | |
| 189 if ( size < count ) return false; | |
| 190 if ( size <= base ) return false; | |
| 191 if ( 0 > count ) return false; | |
| 192 if ( 0 > base ) return false; | |
| 193 | |
| 194 // Comments about needing 2 queues elided; they're not true in this | |
| 195 // immediate-dispatch model. I think we could get away with only | |
| 196 // one queue now, biut is it worth it? 4 bytes of redundant info | |
| 197 // buys a lot of correctness. | |
| 198 | |
| 199 case cyg_none: | |
| 200 default: | |
| 201 break; | |
| 202 }; | |
| 203 | |
| 204 return true; | |
| 205 } | |
| 206 | |
| 207 #endif | |
| 208 | |
| 209 | |
| 210 // ------------------------------------------------------------------------- | |
| 211 // From here downwards, these are the major functions of the template; if | |
| 212 // being genuinely used as a template they should probably not be inlined. | |
| 213 // If being used to construct a specific class, with explicit functions, | |
| 214 // then they should be. This is controlled by: | |
| 215 | |
| 216 #ifdef CYGIMP_MBOXT_INLINE | |
| 217 #define CYG_MBOXT_INLINE inline | |
| 218 #else | |
| 219 #define CYG_MBOXT_INLINE | |
| 220 #endif | |
| 221 | |
| 222 // ------------------------------------------------------------------------- | |
| 223 // Get an item, or wait for one to arrive | |
| 224 | |
| 225 template <class T, cyg_count32 QUEUE_SIZE> | |
| 226 CYG_MBOXT_INLINE cyg_bool | |
| 227 Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem ) | |
| 228 { | |
| 229 CYG_REPORT_FUNCTION(); | |
| 230 Cyg_Thread *self = Cyg_Thread::self(); | |
| 231 | |
| 232 // Prevent preemption | |
| 233 Cyg_Scheduler::lock(); | |
| 234 | |
| 235 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 236 | |
| 237 CYG_INSTRUMENT_MBOXT(GET, this, count); | |
| 238 | |
| 239 if ( 0 < count ) { | |
| 240 CYG_INSTRUMENT_MBOXT(GOT, this, count); | |
| 241 | |
| 242 ritem = itemqueue[ (count--, base++) ]; | |
| 243 CYG_ASSERT( 0 <= count, "Count went -ve" ); | |
| 244 CYG_ASSERT( size >= base, "Base overflow" ); | |
| 245 | |
| 246 if ( size <= base ) | |
| 247 base = 0; | |
| 248 | |
| 249 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 250 wakeup_putter(); | |
| 251 #endif | |
| 252 | |
| 253 // Unlock the scheduler and definitely switch threads | |
| 254 Cyg_Scheduler::unlock(); | |
| 255 | |
| 256 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 257 CYG_REPORT_RETVAL( true ); | |
| 258 return true; | |
| 259 } | |
| 260 | |
| 261 self->set_wait_info( (CYG_ADDRWORD)&ritem ); | |
| 262 self->set_sleep_reason( Cyg_Thread::WAIT ); | |
| 263 self->sleep(); | |
| 264 get_threadq.enqueue( self ); | |
| 265 | |
| 266 CYG_INSTRUMENT_MBOXT(WAIT, this, count); | |
| 267 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), | |
| 268 "Called with non-zero scheduler lock"); | |
| 269 | |
| 270 // Unlock scheduler and allow other threads to run | |
| 271 Cyg_Scheduler::unlock(); | |
| 272 | |
| 273 cyg_bool result = true; | |
| 274 switch( self->get_wake_reason() ) | |
| 275 { | |
| 276 case Cyg_Thread::DESTRUCT: | |
| 277 case Cyg_Thread::BREAK: | |
| 278 result = false; | |
| 279 break; | |
| 280 | |
| 281 case Cyg_Thread::EXIT: | |
| 282 self->exit(); | |
| 283 break; | |
| 284 | |
| 285 default: | |
| 286 break; | |
| 287 } | |
| 288 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 289 CYG_REPORT_RETVAL( result ); | |
| 290 return result; | |
| 291 } | |
| 292 | |
| 293 | |
| 294 // ------------------------------------------------------------------------- | |
| 295 // Try to get an item with an absolute timeout and return success. | |
| 296 | |
| 297 #ifdef CYGFUN_KERNEL_THREADS_TIMER | |
| 298 template <class T, cyg_count32 QUEUE_SIZE> | |
| 299 CYG_MBOXT_INLINE cyg_bool | |
| 300 Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem, cyg_tick_count abs_timeout ) | |
| 301 { | |
| 302 CYG_REPORT_FUNCTION(); | |
| 303 | |
| 304 Cyg_Thread *self = Cyg_Thread::self(); | |
| 305 | |
| 306 // Prevent preemption | |
| 307 Cyg_Scheduler::lock(); | |
| 308 | |
| 309 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 310 | |
| 311 CYG_INSTRUMENT_MBOXT(GET, this, count); | |
| 312 | |
| 313 if ( 0 < count ) { | |
| 314 CYG_INSTRUMENT_MBOXT(GOT, this, count); | |
| 315 | |
| 316 ritem = itemqueue[ (count--, base++) ]; | |
| 317 CYG_ASSERT( 0 <= count, "Count went -ve" ); | |
| 318 CYG_ASSERT( size >= base, "Base overflow" ); | |
| 319 | |
| 320 if ( size <= base ) | |
| 321 base = 0; | |
| 322 | |
| 323 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 324 wakeup_putter(); | |
| 325 #endif | |
| 326 | |
| 327 // Unlock the scheduler and maybe switch threads | |
| 328 Cyg_Scheduler::unlock(); | |
| 329 | |
| 330 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 331 CYG_REPORT_RETVAL( true ); | |
| 332 return true; | |
| 333 } | |
| 334 | |
| 335 // Set the timer | |
| 336 self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); | |
| 337 | |
| 338 // If the timeout is in the past, the wake reason will have been set to | |
| 339 // something other than NONE already. If so, skip the wait and go | |
| 340 // straight to unlock. | |
| 341 | |
| 342 if( Cyg_Thread::NONE == self->get_wake_reason() ) { | |
| 343 self->set_wait_info( (CYG_ADDRWORD)&ritem ); | |
| 344 self->sleep(); | |
| 345 get_threadq.enqueue( self ); | |
| 346 | |
| 347 CYG_INSTRUMENT_MBOXT(WAIT, this, count); | |
| 348 } | |
| 349 | |
| 350 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), | |
| 351 "Called with non-zero scheduler lock"); | |
| 352 | |
| 353 // Unlock scheduler and allow other threads to run | |
| 354 Cyg_Scheduler::unlock(); | |
| 355 | |
| 356 // clear the timer; if it actually fired, no worries. | |
| 357 self->clear_timer(); | |
| 358 | |
| 359 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 360 | |
| 361 cyg_bool result = true; | |
| 362 switch( self->get_wake_reason() ) | |
| 363 { | |
| 364 case Cyg_Thread::TIMEOUT: | |
| 365 result = false; | |
| 366 CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count); | |
| 367 break; | |
| 368 | |
| 369 case Cyg_Thread::DESTRUCT: | |
| 370 case Cyg_Thread::BREAK: | |
| 371 result = false; | |
| 372 break; | |
| 373 | |
| 374 case Cyg_Thread::EXIT: | |
| 375 self->exit(); | |
| 376 break; | |
| 377 | |
| 378 default: | |
| 379 break; | |
| 380 } | |
| 381 | |
| 382 CYG_REPORT_RETVAL( result ); | |
| 383 return result; | |
| 384 } | |
| 385 #endif // CYGFUN_KERNEL_THREADS_TIMER | |
| 386 | |
| 387 // ------------------------------------------------------------------------- | |
| 388 // Try to get an item and return success. | |
| 389 | |
| 390 template <class T, cyg_count32 QUEUE_SIZE> | |
| 391 CYG_MBOXT_INLINE cyg_bool | |
| 392 Cyg_Mboxt2<T,QUEUE_SIZE>::tryget( T &ritem ) | |
| 393 { | |
| 394 CYG_REPORT_FUNCTION(); | |
| 395 | |
| 396 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 397 | |
| 398 // Prevent preemption | |
| 399 Cyg_Scheduler::lock(); | |
| 400 | |
| 401 CYG_INSTRUMENT_MBOXT(TRY, this, count); | |
| 402 | |
| 403 cyg_bool result = ( 0 < count ); | |
| 404 // If the mboxt2 is not empty, grab an item and return it. | |
| 405 if ( result ) { | |
| 406 ritem = itemqueue[ (count--, base++) ]; | |
| 407 CYG_ASSERT( 0 <= count, "Count went -ve" ); | |
| 408 CYG_ASSERT( size >= base, "Base overflow" ); | |
| 409 if ( size <= base ) | |
| 410 base = 0; | |
| 411 | |
| 412 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 413 wakeup_putter(); | |
| 414 #endif | |
| 415 } | |
| 416 | |
| 417 // Unlock the scheduler and maybe switch threads | |
| 418 Cyg_Scheduler::unlock(); | |
| 419 CYG_REPORT_RETVAL( result ); | |
| 420 return result; | |
| 421 } | |
| 422 | |
| 423 // ------------------------------------------------------------------------- | |
| 424 // get next item without removing it | |
| 425 template <class T, cyg_count32 QUEUE_SIZE> | |
| 426 CYG_MBOXT_INLINE cyg_bool | |
| 427 Cyg_Mboxt2<T,QUEUE_SIZE>::peek_item( T &ritem ) | |
| 428 { | |
| 429 CYG_REPORT_FUNCTION(); | |
| 430 | |
| 431 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 432 | |
| 433 // Prevent preemption | |
| 434 Cyg_Scheduler::lock(); | |
| 435 | |
| 436 CYG_INSTRUMENT_MBOXT(TRY, this, count); | |
| 437 | |
| 438 cyg_bool result = ( 0 < count ); | |
| 439 // If the mboxt2 is not empty, grab an item and return it. | |
| 440 if ( result ) | |
| 441 ritem = itemqueue[ base ]; | |
| 442 | |
| 443 // Unlock the scheduler and maybe switch threads | |
| 444 Cyg_Scheduler::unlock(); | |
| 445 CYG_REPORT_RETVAL( result ); | |
| 446 return result; | |
| 447 } | |
| 448 | |
| 449 // ------------------------------------------------------------------------- | |
| 450 // Put an item in the queue; wait if full. | |
| 451 | |
| 452 #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 453 template <class T, cyg_count32 QUEUE_SIZE> | |
| 454 CYG_MBOXT_INLINE cyg_bool | |
| 455 Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item ) | |
| 456 { | |
| 457 CYG_REPORT_FUNCTION(); | |
| 458 | |
| 459 Cyg_Thread *self = Cyg_Thread::self(); | |
| 460 | |
| 461 // Prevent preemption | |
| 462 Cyg_Scheduler::lock(); | |
| 463 | |
| 464 CYG_INSTRUMENT_MBOXT(PUT, this, count); | |
| 465 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 466 | |
| 467 if ( size == count ) { | |
| 468 CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" ); | |
| 469 | |
| 470 self->set_wait_info( (CYG_ADDRWORD)&item ); | |
| 471 self->set_sleep_reason( Cyg_Thread::WAIT ); | |
| 472 self->sleep(); | |
| 473 put_threadq.enqueue( self ); | |
| 474 | |
| 475 CYG_INSTRUMENT_MBOXT(WAIT, this, count); | |
| 476 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), | |
| 477 "Called with non-zero scheduler lock"); | |
| 478 | |
| 479 // when this returns, our item is in the queue. | |
| 480 Cyg_Scheduler::unlock(); // unlock, switch threads | |
| 481 | |
| 482 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 483 | |
| 484 cyg_bool result = true; | |
| 485 switch( self->get_wake_reason() ) | |
| 486 { | |
| 487 case Cyg_Thread::DESTRUCT: | |
| 488 case Cyg_Thread::BREAK: | |
| 489 result = false; | |
| 490 break; | |
| 491 | |
| 492 case Cyg_Thread::EXIT: | |
| 493 self->exit(); | |
| 494 break; | |
| 495 | |
| 496 default: | |
| 497 break; | |
| 498 } | |
| 499 CYG_REPORT_RETVAL( result ); | |
| 500 return result; | |
| 501 } | |
| 502 | |
| 503 if ( !get_threadq.empty() ) { | |
| 504 wakeup_winner( item ); | |
| 505 Cyg_Scheduler::unlock(); // unlock, maybe switch threads | |
| 506 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 507 CYG_REPORT_RETVAL( true ); | |
| 508 return true; | |
| 509 } | |
| 510 | |
| 511 cyg_count32 in = base + (count++); | |
| 512 if ( size <= in ) | |
| 513 in -= size; | |
| 514 | |
| 515 CYG_ASSERT( size > in, "in overflow" ); | |
| 516 CYG_ASSERT( 0 <= in, "in overflow" ); | |
| 517 CYG_ASSERT( size >= count, "count overflow" ); | |
| 518 | |
| 519 itemqueue[ in ] = item; | |
| 520 | |
| 521 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 522 | |
| 523 // Unlock the scheduler and maybe switch threads | |
| 524 Cyg_Scheduler::unlock(); | |
| 525 CYG_REPORT_RETVAL( true ); | |
| 526 return true; | |
| 527 } | |
| 528 | |
| 529 // ------------------------------------------------------------------------- | |
| 530 // Put an item in the queue; wait if full, with an absolute timeout; | |
| 531 // return success. | |
| 532 | |
| 533 #ifdef CYGFUN_KERNEL_THREADS_TIMER | |
| 534 template <class T, cyg_count32 QUEUE_SIZE> | |
| 535 CYG_MBOXT_INLINE cyg_bool | |
| 536 Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item, cyg_tick_count abs_timeout ) | |
| 537 { | |
| 538 CYG_REPORT_FUNCTION(); | |
| 539 | |
| 540 Cyg_Thread *self = Cyg_Thread::self(); | |
| 541 | |
| 542 // Prevent preemption | |
| 543 Cyg_Scheduler::lock(); | |
| 544 | |
| 545 CYG_INSTRUMENT_MBOXT(PUT, this, count); | |
| 546 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 547 | |
| 548 if ( size == count ) { | |
| 549 | |
| 550 CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" ); | |
| 551 | |
| 552 // Set the timer | |
| 553 self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); | |
| 554 | |
| 555 // If the timeout is in the past, the wake reason will have been set to | |
| 556 // something other than NONE already. If so, skip the wait and go | |
| 557 // straight to unlock. | |
| 558 | |
| 559 if( Cyg_Thread::NONE == self->get_wake_reason() ) { | |
| 560 self->set_wait_info( (CYG_ADDRWORD)&item ); | |
| 561 self->sleep(); | |
| 562 put_threadq.enqueue( self ); | |
| 563 | |
| 564 CYG_INSTRUMENT_MBOXT(WAIT, this, count); | |
| 565 } | |
| 566 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), | |
| 567 "Called with non-zero scheduler lock"); | |
| 568 | |
| 569 // when this returns, our item is in the queue. | |
| 570 Cyg_Scheduler::unlock(); // unlock, switch threads | |
| 571 | |
| 572 // clear the timer; if it actually fired, no worries. | |
| 573 self->clear_timer(); | |
| 574 | |
| 575 cyg_bool result = true; | |
| 576 switch( self->get_wake_reason() ) | |
| 577 { | |
| 578 case Cyg_Thread::TIMEOUT: | |
| 579 result = false; | |
| 580 CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count); | |
| 581 break; | |
| 582 | |
| 583 case Cyg_Thread::DESTRUCT: | |
| 584 case Cyg_Thread::BREAK: | |
| 585 result = false; | |
| 586 break; | |
| 587 | |
| 588 case Cyg_Thread::EXIT: | |
| 589 self->exit(); | |
| 590 break; | |
| 591 | |
| 592 default: | |
| 593 break; | |
| 594 } | |
| 595 | |
| 596 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 597 CYG_REPORT_RETVAL( result ); | |
| 598 return result; | |
| 599 } | |
| 600 | |
| 601 | |
| 602 if ( !get_threadq.empty() ) { | |
| 603 wakeup_winner( item ); | |
| 604 Cyg_Scheduler::unlock(); // unlock, maybe switch threads | |
| 605 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 606 CYG_REPORT_RETVAL( true ); | |
| 607 return true; | |
| 608 } | |
| 609 | |
| 610 cyg_count32 in = base + (count++); | |
| 611 if ( size <= in ) | |
| 612 in -= size; | |
| 613 | |
| 614 CYG_ASSERT( size > in, "in overflow" ); | |
| 615 CYG_ASSERT( 0 <= in, "in overflow" ); | |
| 616 CYG_ASSERT( size >= count, "count overflow" ); | |
| 617 | |
| 618 itemqueue[ in ] = item; | |
| 619 | |
| 620 // Unlock the scheduler and maybe switch threads | |
| 621 Cyg_Scheduler::unlock(); | |
| 622 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 623 CYG_REPORT_RETVAL( true ); | |
| 624 return true; | |
| 625 } | |
| 626 #endif // CYGFUN_KERNEL_THREADS_TIMER | |
| 627 #endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT | |
| 628 | |
| 629 // ------------------------------------------------------------------------- | |
| 630 // Try to put an item in the queue and return success; queue may be full. | |
| 631 | |
| 632 template <class T, cyg_count32 QUEUE_SIZE> | |
| 633 CYG_MBOXT_INLINE cyg_bool | |
| 634 Cyg_Mboxt2<T,QUEUE_SIZE>::tryput( const T item ) | |
| 635 { | |
| 636 CYG_REPORT_FUNCTION(); | |
| 637 | |
| 638 // Prevent preemption | |
| 639 Cyg_Scheduler::lock(); | |
| 640 | |
| 641 CYG_INSTRUMENT_MBOXT(PUT, this, count); | |
| 642 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 643 | |
| 644 if ( size == count ) { | |
| 645 CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" ); | |
| 646 Cyg_Scheduler::unlock(); // unlock, maybe switch threads | |
| 647 CYG_REPORT_RETVAL( false ); | |
| 648 return false; // the mboxt2 is full | |
| 649 } | |
| 650 | |
| 651 if ( !get_threadq.empty() ) { | |
| 652 CYG_ASSERT( 0 == count, "Threads waiting AND queue not empty" ); | |
| 653 wakeup_winner( item ); | |
| 654 Cyg_Scheduler::unlock(); // unlock, maybe switch threads | |
| 655 CYG_REPORT_RETVAL( true ); | |
| 656 return true; | |
| 657 } | |
| 658 | |
| 659 cyg_count32 in = base + (count++); | |
| 660 if ( size <= in ) | |
| 661 in -= size; | |
| 662 | |
| 663 CYG_ASSERT( size > in, "in overflow" ); | |
| 664 CYG_ASSERT( 0 <= in, "in overflow" ); | |
| 665 CYG_ASSERT( size >= count, "count overflow" ); | |
| 666 | |
| 667 itemqueue[ in ] = item; | |
| 668 | |
| 669 CYG_ASSERTCLASS( this, "Bad this pointer"); | |
| 670 | |
| 671 // Unlock the scheduler and maybe switch threads | |
| 672 Cyg_Scheduler::unlock(); | |
| 673 | |
| 674 CYG_REPORT_RETVAL( true ); | |
| 675 return true; | |
| 676 } | |
| 677 | |
| 678 | |
| 679 // ------------------------------------------------------------------------- | |
| 680 #endif // ifndef CYGONCE_KERNEL_MBOXT2_INL | |
| 681 // EOF mboxt2.inl |
