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