Mercurial > ecos
comparison packages/kernel/current/src/sched/lottery.cxx @ 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 //========================================================================== | |
| 2 // | |
| 3 // sched/lottery.cxx | |
| 4 // | |
| 5 // Lottery scheduler class implementation | |
| 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 | |
| 25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. | |
| 26 // ------------------------------------------- | |
| 27 // | |
| 28 //####COPYRIGHTEND#### | |
| 29 //========================================================================== | |
| 30 //#####DESCRIPTIONBEGIN#### | |
| 31 // | |
| 32 // Author(s): nickg | |
| 33 // Contributors: nickg | |
| 34 // Date: 1997-09-16 | |
| 35 // Purpose: Lottery scheduler class implementation | |
| 36 // Description: This file contains the implementations of | |
| 37 // Cyg_Scheduler_Implementation and | |
| 38 // Cyg_SchedThread_Implementation. | |
| 39 // | |
| 40 // | |
| 41 //####DESCRIPTIONEND#### | |
| 42 // | |
| 43 //========================================================================== | |
| 44 | |
| 45 #include <pkgconf/kernel.h> | |
| 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 | |
| 51 #include <cyg/kernel/sched.hxx> // our header | |
| 52 #include <cyg/kernel/intr.hxx> // interrupt defines, for Cyg_HAL_Clock | |
| 53 | |
| 54 #include <cyg/hal/hal_arch.h> // Architecture specific definitions | |
| 55 | |
| 56 | |
| 57 #include <cyg/kernel/thread.inl> // thread inlines | |
| 58 #include <cyg/kernel/sched.inl> // scheduler inlines | |
| 59 | |
| 60 #ifdef CYGSEM_KERNEL_SCHED_LOTTERY | |
| 61 | |
| 62 #define CYG_ENABLE_TRACE 1 | |
| 63 | |
| 64 //========================================================================== | |
| 65 // Cyg_Scheduler_Implementation class static members | |
| 66 | |
| 67 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE | |
| 68 | |
| 69 cyg_count32 Cyg_Scheduler_Implementation::timeslice_count = | |
| 70 CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS; | |
| 71 | |
| 72 #endif | |
| 73 | |
| 74 //========================================================================== | |
| 75 // Cyg_Scheduler_Implementation class members | |
| 76 | |
| 77 // ------------------------------------------------------------------------- | |
| 78 // Constructor. | |
| 79 | |
| 80 Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation() | |
| 81 { | |
| 82 CYG_REPORT_FUNCTION(); | |
| 83 | |
| 84 total_tickets = 0; | |
| 85 rand_seed = 1; | |
| 86 } | |
| 87 | |
| 88 // ------------------------------------------------------------------------- | |
| 89 // Choose the best thread to run next | |
| 90 | |
| 91 Cyg_Thread *Cyg_Scheduler_Implementation::schedule() | |
| 92 { | |
| 93 CYG_REPORT_FUNCTION(); | |
| 94 | |
| 95 #ifdef CYG_HAL_POWERPC | |
| 96 | |
| 97 // PowerPc specific version of random number generator. | |
| 98 register cyg_int32 r1 asm("r4"); | |
| 99 r1 = rand_seed; | |
| 100 asm( | |
| 101 "li 7,0;" | |
| 102 "ori 7,7,33614;" | |
| 103 "mulhwu 5,7,%0;" | |
| 104 "mullw 6,7,%0;" | |
| 105 "srawi 6,6,1;" | |
| 106 "add %0,5,6;" | |
| 107 "cmpwi %0,0;" | |
| 108 "bge 1f;" | |
| 109 "slwi %0,%0,1;" | |
| 110 "srwi %0,%0,1;" | |
| 111 "addi %0,%0,1;" | |
| 112 "1:;" | |
| 113 : "=r"(r1) | |
| 114 : "0"(r1) | |
| 115 : "r5", "r6", "r7" | |
| 116 ); | |
| 117 rand_seed = r1; | |
| 118 | |
| 119 #else | |
| 120 #if 1 | |
| 121 rand_seed = (rand_seed * 1103515245) + 1234; | |
| 122 cyg_int32 r1 = rand_seed & 0x7FFFFFFF; | |
| 123 #else | |
| 124 // Generic implementation of RNG. | |
| 125 #if( CYG_BYTEORDER == CYG_MSBFIRST ) | |
| 126 #define _LO 1 | |
| 127 #define _HI 0 | |
| 128 #else | |
| 129 #define _LO 0 | |
| 130 #define _HI 1 | |
| 131 #endif | |
| 132 union { cyg_int64 r64; cyg_int32 r32[2]; } u; | |
| 133 u.r64 = (cyg_int64)rand_seed * 33614LL; | |
| 134 cyg_int32 r1 = u.r32[_HI] + (u.r32[_LO]>>1); | |
| 135 if( r1 < 0 ) | |
| 136 r1 = (r1 & 0x7FFFFFFF) + 1; | |
| 137 rand_seed = r1; | |
| 138 #undef _LO | |
| 139 #undef _HI | |
| 140 #endif | |
| 141 #endif | |
| 142 | |
| 143 cyg_int32 ticket = r1 % total_tickets; | |
| 144 cyg_int32 tick = ticket; | |
| 145 Cyg_Thread *thread = run_queue.highpri(); | |
| 146 | |
| 147 // Search the run queue for the thread with the | |
| 148 // given ticket. | |
| 149 while( ticket > 0 ) | |
| 150 { | |
| 151 ticket -= thread->priority; | |
| 152 if( ticket <= 0 ) break; | |
| 153 thread = thread->next; | |
| 154 | |
| 155 CYG_ASSERT( thread != run_queue.highpri(), "Looping in scheduler"); | |
| 156 } | |
| 157 | |
| 158 CYG_TRACE3( CYG_ENABLE_TRACE, | |
| 159 "seed %08x ticket %d thread %08x", | |
| 160 rand_seed, tick, thread); | |
| 161 | |
| 162 // If the thread has any compensation tickets, take them away since | |
| 163 // it has just won. | |
| 164 | |
| 165 if( thread->compensation_tickets > 0 ) | |
| 166 { | |
| 167 thread->priority -= thread->compensation_tickets; | |
| 168 total_tickets -= thread->compensation_tickets; | |
| 169 thread->compensation_tickets = 0; | |
| 170 } | |
| 171 | |
| 172 // Re-insert thread at head of list. This reduces runtime by | |
| 173 // putting the large ticket holders at the front of the list. | |
| 174 | |
| 175 // run_queue.remove(thread); | |
| 176 // run_queue.enqueue(thread); | |
| 177 | |
| 178 CYG_CHECK_DATA_PTR( thread, "Invalid next thread pointer"); | |
| 179 CYG_ASSERTCLASS( thread, "Bad next thread" ); | |
| 180 | |
| 181 return thread; | |
| 182 } | |
| 183 | |
| 184 // ------------------------------------------------------------------------- | |
| 185 | |
| 186 void Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread) | |
| 187 { | |
| 188 CYG_REPORT_FUNCTION(); | |
| 189 | |
| 190 // If the thread is on some other queue, remove it | |
| 191 // here. | |
| 192 if( thread->queue != NULL ) | |
| 193 { | |
| 194 thread->queue->remove(thread); | |
| 195 thread->queue = NULL; | |
| 196 } | |
| 197 | |
| 198 total_tickets += thread->priority; | |
| 199 | |
| 200 run_queue.enqueue(thread); | |
| 201 } | |
| 202 | |
| 203 // ------------------------------------------------------------------------- | |
| 204 | |
| 205 void Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread) | |
| 206 { | |
| 207 CYG_REPORT_FUNCTION(); | |
| 208 | |
| 209 run_queue.remove(thread); | |
| 210 | |
| 211 total_tickets -= thread->priority; | |
| 212 | |
| 213 // Compensate the thread for the segment of the quantum that | |
| 214 // it used. This makes it more likely to win the lottery next time | |
| 215 // it is scheduled. We only do this for threads that have voluntarily | |
| 216 // given up the CPU. | |
| 217 | |
| 218 // if( thread->get_state() != Cyg_Thread::RUNNING ) | |
| 219 { | |
| 220 #if 0 | |
| 221 cyg_uint32 hal_ticks; | |
| 222 HAL_CLOCK_READ( &hal_ticks ); | |
| 223 thread->compensation_tickets = thread->priority * | |
| 224 CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / hal_ticks; | |
| 225 #else | |
| 226 thread->compensation_tickets = (thread->priority * | |
| 227 CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS) / timeslice_count; | |
| 228 | |
| 229 #endif | |
| 230 thread->priority += thread->compensation_tickets; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 // ------------------------------------------------------------------------- | |
| 235 // register thread with scheduler | |
| 236 | |
| 237 void Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread) | |
| 238 { | |
| 239 CYG_REPORT_FUNCTION(); | |
| 240 | |
| 241 // No registration necessary in this scheduler | |
| 242 } | |
| 243 | |
| 244 // ------------------------------------------------------------------------- | |
| 245 | |
| 246 // deregister thread | |
| 247 void Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread) | |
| 248 { | |
| 249 CYG_REPORT_FUNCTION(); | |
| 250 | |
| 251 // No registration necessary in this scheduler | |
| 252 } | |
| 253 | |
| 254 // ------------------------------------------------------------------------- | |
| 255 // Test the given priority for uniqueness | |
| 256 | |
| 257 cyg_bool Cyg_Scheduler_Implementation::unique( cyg_priority priority) | |
| 258 { | |
| 259 CYG_REPORT_FUNCTION(); | |
| 260 | |
| 261 // Priorities are not unique | |
| 262 return true; | |
| 263 } | |
| 264 | |
| 265 //========================================================================== | |
| 266 // Support for timeslicing option | |
| 267 | |
| 268 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE | |
| 269 | |
| 270 void Cyg_Scheduler_Implementation::timeslice() | |
| 271 { | |
| 272 CYG_REPORT_FUNCTION(); | |
| 273 | |
| 274 if( --timeslice_count <= 0 ) | |
| 275 { | |
| 276 CYG_INSTRUMENT_SCHED(TIMESLICE,0,0); | |
| 277 | |
| 278 // Force a reschedule on each timeslice | |
| 279 need_reschedule = true; | |
| 280 timeslice_count = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 #endif | |
| 285 | |
| 286 //========================================================================== | |
| 287 // Cyg_Cyg_SchedThread_Implementation class members | |
| 288 | |
| 289 Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation | |
| 290 ( | |
| 291 CYG_ADDRWORD sched_info | |
| 292 ) | |
| 293 { | |
| 294 CYG_REPORT_FUNCTION(); | |
| 295 | |
| 296 priority = cyg_priority(sched_info); | |
| 297 | |
| 298 // point the next and prev field at this thread. | |
| 299 | |
| 300 next = prev = CYG_CLASSFROMBASE(Cyg_Thread, | |
| 301 Cyg_SchedThread_Implementation, | |
| 302 this); | |
| 303 } | |
| 304 | |
| 305 // ------------------------------------------------------------------------- | |
| 306 // Insert thread in front of this | |
| 307 | |
| 308 void Cyg_SchedThread_Implementation::insert( Cyg_Thread *thread) | |
| 309 { | |
| 310 CYG_REPORT_FUNCTION(); | |
| 311 | |
| 312 thread->next = CYG_CLASSFROMBASE(Cyg_Thread, | |
| 313 Cyg_SchedThread_Implementation, | |
| 314 this); | |
| 315 thread->prev = prev; | |
| 316 prev->next = thread; | |
| 317 prev = thread; | |
| 318 } | |
| 319 | |
| 320 // ------------------------------------------------------------------------- | |
| 321 // remove this from queue | |
| 322 | |
| 323 void Cyg_SchedThread_Implementation::remove() | |
| 324 { | |
| 325 CYG_REPORT_FUNCTION(); | |
| 326 | |
| 327 next->prev = prev; | |
| 328 prev->next = next; | |
| 329 next = prev = CYG_CLASSFROMBASE(Cyg_Thread, | |
| 330 Cyg_SchedThread_Implementation, | |
| 331 this); | |
| 332 } | |
| 333 | |
| 334 // ------------------------------------------------------------------------- | |
| 335 // Yield the processor to another thread | |
| 336 | |
| 337 void Cyg_SchedThread_Implementation::yield() | |
| 338 { | |
| 339 CYG_REPORT_FUNCTION(); | |
| 340 | |
| 341 | |
| 342 } | |
| 343 | |
| 344 //========================================================================== | |
| 345 // Cyg_ThreadQueue_Implementation class members | |
| 346 | |
| 347 void Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread) | |
| 348 { | |
| 349 CYG_REPORT_FUNCTION(); | |
| 350 | |
| 351 // Always put thread at head of queue | |
| 352 if( queue == NULL ) queue = thread; | |
| 353 else | |
| 354 { | |
| 355 queue->insert(thread); | |
| 356 // queue->next->insert(thread); | |
| 357 // queue = thread; | |
| 358 } | |
| 359 | |
| 360 thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue, | |
| 361 Cyg_ThreadQueue_Implementation, | |
| 362 this); | |
| 363 } | |
| 364 | |
| 365 // ------------------------------------------------------------------------- | |
| 366 | |
| 367 Cyg_Thread *Cyg_ThreadQueue_Implementation::dequeue() | |
| 368 { | |
| 369 CYG_REPORT_FUNCTION(); | |
| 370 | |
| 371 if( queue == NULL ) return NULL; | |
| 372 | |
| 373 Cyg_Thread *thread = queue; | |
| 374 | |
| 375 if( thread->next == thread ) | |
| 376 { | |
| 377 // sole thread on list, NULL out ptr | |
| 378 queue = NULL; | |
| 379 } | |
| 380 else | |
| 381 { | |
| 382 // advance to next and remove thread | |
| 383 queue = thread->next; | |
| 384 thread->remove(); | |
| 385 } | |
| 386 | |
| 387 thread->queue = NULL; | |
| 388 | |
| 389 return thread; | |
| 390 } | |
| 391 | |
| 392 // ------------------------------------------------------------------------- | |
| 393 | |
| 394 Cyg_Thread *Cyg_ThreadQueue_Implementation::highpri() | |
| 395 { | |
| 396 CYG_REPORT_FUNCTION(); | |
| 397 | |
| 398 return queue; | |
| 399 } | |
| 400 | |
| 401 // ------------------------------------------------------------------------- | |
| 402 | |
| 403 void Cyg_ThreadQueue_Implementation::remove(Cyg_Thread *thread) | |
| 404 { | |
| 405 CYG_REPORT_FUNCTION(); | |
| 406 | |
| 407 // If the thread we want is the at the head | |
| 408 // of the list, and is on its own, clear the | |
| 409 // list and return. Otherwise advance to the | |
| 410 // next thread and remove ours. If the thread | |
| 411 // is not at the head of the list, just dequeue | |
| 412 // it. | |
| 413 | |
| 414 thread->queue = NULL; | |
| 415 | |
| 416 if( queue == thread ) | |
| 417 { | |
| 418 if( thread->next == thread ) | |
| 419 { | |
| 420 queue = NULL; | |
| 421 return; | |
| 422 } | |
| 423 else queue = thread->next; | |
| 424 } | |
| 425 | |
| 426 thread->Cyg_SchedThread_Implementation::remove(); | |
| 427 | |
| 428 } | |
| 429 | |
| 430 // ------------------------------------------------------------------------- | |
| 431 // Rotate the front thread on the queue to the back. | |
| 432 | |
| 433 void Cyg_ThreadQueue_Implementation::rotate() | |
| 434 { | |
| 435 CYG_REPORT_FUNCTION(); | |
| 436 | |
| 437 queue = queue->next; | |
| 438 } | |
| 439 | |
| 440 // ------------------------------------------------------------------------- | |
| 441 | |
| 442 #endif | |
| 443 | |
| 444 // ------------------------------------------------------------------------- | |
| 445 // EOF sched/lottery.cxx |
