comparison packages/kernel/current/src/sched/mlqueue.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/mlqueue.cxx
4 //
5 // Multi-level queue 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: Multilevel queue scheduler class implementation
36 // Description: This file contains the implementations of
37 // Cyg_Scheduler_Implementation and Cyg_SchedThread_Implementation.
38 //
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
50 #include <cyg/kernel/sched.hxx> // our header
51
52 #include <cyg/hal/hal_arch.h> // Architecture specific definitions
53
54 #include <cyg/kernel/thread.inl> // thread inlines
55 #include <cyg/kernel/sched.inl> // scheduler inlines
56
57 #ifdef CYGSEM_KERNEL_SCHED_MLQUEUE
58
59 //-------------------------------------------------------------------------
60 // Some local tracing control - a default.
61 #ifdef CYGDBG_USE_TRACING
62 # if !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_SIMPLE ) && \
63 !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_FANCY )
64 // ie. not a tracing implementation that takes a long time to output
65
66 # ifndef CYGDBG_KERNEL_TRACE_TIMESLICE
67 # define CYGDBG_KERNEL_TRACE_TIMESLICE
68 # endif // control not already defined
69
70 # endif // trace implementation not ..._SIMPLE && not ..._FANCY
71 #endif // CYGDBG_USE_TRACING
72
73 //==========================================================================
74 // Cyg_Scheduler_Implementation class static members
75
76 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
77
78 cyg_ucount32 Cyg_Scheduler_Implementation::timeslice_count =
79 CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
80
81 #endif
82
83
84 //==========================================================================
85 // Cyg_Scheduler_Implementation class members
86
87 // -------------------------------------------------------------------------
88 // Constructor.
89
90 Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
91 {
92 CYG_REPORT_FUNCTION();
93
94 queue_map = 0;
95 }
96
97 // -------------------------------------------------------------------------
98 // Choose the best thread to run next
99
100 Cyg_Thread *Cyg_Scheduler_Implementation::schedule()
101 {
102 CYG_REPORT_FUNCTION();
103
104 // The run queue may _never_ be empty, there is always
105 // an idle thread at the lowest priority.
106
107 CYG_ASSERT( queue_map != 0, "Run queue empty");
108 CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
109 CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
110
111 register cyg_uint32 index;
112
113 HAL_LSBIT_INDEX(index, queue_map);
114
115 Cyg_Thread *thread = run_queue[index].highpri();
116
117 CYG_ASSERT( thread != NULL , "No threads in run queue");
118
119 return thread;
120 }
121
122 // -------------------------------------------------------------------------
123
124 void Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
125 {
126 CYG_REPORT_FUNCTION();
127
128 cyg_priority pri = thread->priority;
129 Cyg_ThreadQueue_Implementation *queue = &run_queue[pri];
130
131 // If the thread is on some other queue, remove it
132 // here.
133 if( thread->queue != NULL )
134 {
135 thread->queue->remove(thread);
136 thread->queue = NULL;
137 }
138
139 if( queue->empty() )
140 {
141 // set the map bit and ask for a reschedule if this is a
142 // new highest priority thread.
143
144 queue_map |= (1<<pri);
145
146 // If the new thread is higher priority than the
147 // current thread, request a reschedule.
148
149 if( pri < Cyg_Scheduler::get_current_thread()->priority )
150 need_reschedule = true;
151
152 }
153 // else the queue already has an occupant, queue behind him
154
155 CYG_ASSERT( queue_map != 0, "Run queue empty");
156 CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
157 CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
158 // CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
159
160 queue->enqueue(thread);
161 }
162
163 // -------------------------------------------------------------------------
164
165 void Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
166 {
167 CYG_REPORT_FUNCTION();
168
169 CYG_ASSERT( queue_map != 0, "Run queue empty");
170
171 cyg_priority pri = thread->priority;
172 Cyg_ThreadQueue_Implementation *queue = &run_queue[pri];
173
174 CYG_ASSERT( pri != CYG_THREAD_MIN_PRIORITY, "Idle thread trying to sleep!");
175 CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
176 CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
177
178 // remove thread from queue
179 queue->remove(thread);
180
181 if( queue->empty() )
182 {
183 // If this was only thread in
184 // queue, clear map.
185
186 queue_map &= ~(1<<pri);
187 }
188
189 CYG_ASSERT( queue_map != 0, "Run queue empty");
190 CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
191 CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
192 }
193
194 // -------------------------------------------------------------------------
195 // register thread with scheduler
196
197 void Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
198 {
199 CYG_REPORT_FUNCTION();
200
201 // No registration necessary in this scheduler
202 }
203
204 // -------------------------------------------------------------------------
205
206 // deregister thread
207 void Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
208 {
209 CYG_REPORT_FUNCTION();
210
211 // No registration necessary in this scheduler
212 }
213
214 // -------------------------------------------------------------------------
215 // Test the given priority for uniqueness
216
217 cyg_bool Cyg_Scheduler_Implementation::unique( cyg_priority priority)
218 {
219 CYG_REPORT_FUNCTION();
220
221 // Priorities are not unique
222 return true;
223 }
224
225 //==========================================================================
226 // Support for timeslicing option
227
228 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
229
230 void Cyg_Scheduler_Implementation::timeslice()
231 {
232 #ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
233 CYG_REPORT_FUNCTION();
234 #endif
235 CYG_ASSERT( queue_map != 0, "Run queue empty");
236 CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
237
238 if( --timeslice_count == 0 )
239 {
240 CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
241 #ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
242 CYG_TRACE0( true, "quantum consumed, time to reschedule" );
243 #endif
244 // And force the current thread to yield.
245 current_thread->yield();
246 }
247
248 CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
249 CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
250 #ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
251 CYG_REPORT_RETURN();
252 #endif
253 }
254
255 #endif
256
257 //==========================================================================
258 // Cyg_Cyg_SchedThread_Implementation class members
259
260 Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
261 (
262 CYG_ADDRWORD sched_info
263 )
264 {
265 CYG_REPORT_FUNCTION();
266
267 // Create all threads at maximum priority
268 priority = (cyg_priority)sched_info;
269
270 // point the next and prev field at this thread.
271
272 next = prev = CYG_CLASSFROMBASE(Cyg_Thread,
273 Cyg_SchedThread_Implementation,
274 this);
275 }
276
277 // -------------------------------------------------------------------------
278 // Insert thread in front of this
279
280 void Cyg_SchedThread_Implementation::insert( Cyg_Thread *thread)
281 {
282 CYG_REPORT_FUNCTION();
283
284 thread->next = CYG_CLASSFROMBASE(Cyg_Thread,
285 Cyg_SchedThread_Implementation,
286 this);
287 thread->prev = prev;
288 prev->next = thread;
289 prev = thread;
290 }
291
292 // -------------------------------------------------------------------------
293 // remove this from queue
294
295 void Cyg_SchedThread_Implementation::remove()
296 {
297 CYG_REPORT_FUNCTION();
298
299 next->prev = prev;
300 prev->next = next;
301 next = prev = CYG_CLASSFROMBASE(Cyg_Thread,
302 Cyg_SchedThread_Implementation,
303 this);
304 }
305
306 // -------------------------------------------------------------------------
307 // Yield the processor to another thread
308
309 void Cyg_SchedThread_Implementation::yield()
310 {
311 CYG_REPORT_FUNCTION();
312
313 // Prevent preemption
314 Cyg_Scheduler::lock();
315
316 Cyg_Thread *thread = CYG_CLASSFROMBASE(Cyg_Thread,
317 Cyg_SchedThread_Implementation,
318 this);
319
320 // Only do this if this thread is running. If it is not, there
321 // is no point.
322
323 if( thread->get_state() == Cyg_Thread::RUNNING )
324 {
325 // To yield we simply rotate the appropriate
326 // run queue to the next thread and reschedule.
327
328 CYG_ASSERTCLASS( thread, "Bad current thread");
329
330 Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
331
332 CYG_ASSERTCLASS( sched, "Bad scheduler");
333
334 cyg_priority pri = thread->priority;
335 Cyg_ThreadQueue_Implementation *queue = &sched->run_queue[pri];
336
337 queue->rotate();
338
339 if( queue->highpri() != thread )
340 sched->need_reschedule = true;
341 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
342 // Reset the timeslice counter so that this thread gets a full
343 // quantum.
344 else Cyg_Scheduler::reset_timeslice_count();
345 #endif
346 }
347
348 // Unlock the scheduler and switch threads
349 Cyg_Scheduler::unlock();
350
351 }
352
353 // -------------------------------------------------------------------------
354 // Rotate the run queue at a specified priority.
355 // (pri is the decider, no this, so the routine is static)
356
357 void
358 Cyg_SchedThread_Implementation::rotate_queue( cyg_priority pri )
359 {
360 CYG_REPORT_FUNCTION();
361
362 // Prevent preemption
363 Cyg_Scheduler::lock();
364
365 Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
366
367 CYG_ASSERTCLASS( sched, "Bad scheduler");
368
369 Cyg_ThreadQueue_Implementation *queue = &sched->run_queue[pri];
370
371 if ( !queue->empty() ) {
372 queue->rotate();
373 sched->need_reschedule = true;
374 }
375
376 // Unlock the scheduler and switch threads
377 Cyg_Scheduler::unlock();
378
379 }
380
381 //==========================================================================
382 // Cyg_ThreadQueue_Implementation class members
383
384 Cyg_ThreadQueue_Implementation::Cyg_ThreadQueue_Implementation()
385 {
386 CYG_REPORT_FUNCTION();
387
388 queue = NULL; // empty queue
389 }
390
391
392
393 void Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
394 {
395 CYG_REPORT_FUNCTION();
396
397 if( queue == NULL ) queue = thread;
398 else queue->insert(thread);
399
400 thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
401 Cyg_ThreadQueue_Implementation,
402 this);
403
404 }
405
406 // -------------------------------------------------------------------------
407
408 Cyg_Thread *Cyg_ThreadQueue_Implementation::dequeue()
409 {
410 CYG_REPORT_FUNCTION();
411
412 if( queue == NULL ) return NULL;
413
414 Cyg_Thread *thread = queue;
415
416 if( thread->next == thread )
417 {
418 // sole thread on list, NULL out ptr
419 queue = NULL;
420 }
421 else
422 {
423 // advance to next and remove thread
424 queue = thread->next;
425 thread->remove();
426 }
427
428 thread->queue = NULL;
429
430 return thread;
431 }
432
433 // -------------------------------------------------------------------------
434
435 Cyg_Thread *Cyg_ThreadQueue_Implementation::highpri()
436 {
437 CYG_REPORT_FUNCTION();
438
439 return queue;
440 }
441
442 // -------------------------------------------------------------------------
443
444 void Cyg_ThreadQueue_Implementation::remove(Cyg_Thread *thread)
445 {
446 CYG_REPORT_FUNCTION();
447
448 // If the thread we want it the at the head
449 // of the list, and is on its own, clear the
450 // list and return. Otherwise advance to the
451 // next thread and remove ours. If the thread
452 // is not at the head of the list, just dequeue
453 // it.
454
455 thread->queue = NULL;
456
457 if( queue == thread )
458 {
459 if( thread->next == thread )
460 {
461 queue = NULL;
462 return;
463 }
464 else queue = thread->next;
465 }
466
467 thread->Cyg_SchedThread_Implementation::remove();
468
469 }
470
471 // -------------------------------------------------------------------------
472 // Rotate the front thread on the queue to the back.
473
474 void Cyg_ThreadQueue_Implementation::rotate()
475 {
476 CYG_REPORT_FUNCTION();
477
478 queue = queue->next;
479 }
480
481 // -------------------------------------------------------------------------
482
483 #endif
484
485 // -------------------------------------------------------------------------
486 // EOF sched/mlqueue.cxx