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