OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [src/] [sched/] [mlqueue.cxx] - Blame information for rev 838

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      sched/mlqueue.cxx
4
//
5
//      Multi-level queue scheduler class implementation
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    nickg
43
// Contributors: jlarmour
44
// Date:         1999-02-17
45
// Purpose:      Multilevel queue scheduler class implementation
46
// Description:  This file contains the implementations of
47
//               Cyg_Scheduler_Implementation and
48
//               Cyg_SchedThread_Implementation.
49
//              
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include <pkgconf/kernel.h>
56
 
57
#include <cyg/kernel/ktypes.h>         // base kernel types
58
#include <cyg/infra/cyg_trac.h>        // tracing macros
59
#include <cyg/infra/cyg_ass.h>         // assertion macros
60
 
61
#include <cyg/kernel/sched.hxx>        // our header
62
 
63
#include <cyg/hal/hal_arch.h>          // Architecture specific definitions
64
 
65
#include <cyg/kernel/thread.inl>       // thread inlines
66
#include <cyg/kernel/sched.inl>        // scheduler inlines
67
 
68
#ifdef CYGSEM_KERNEL_SCHED_MLQUEUE
69
 
70
//==========================================================================
71
// Cyg_Scheduler_Implementation class static members
72
 
73
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
74
 
75
cyg_ucount32 Cyg_Scheduler_Implementation::timeslice_count[CYGNUM_KERNEL_CPU_MAX];
76
 
77
#endif
78
 
79
 
80
//==========================================================================
81
// Cyg_Scheduler_Implementation class members
82
 
83
// -------------------------------------------------------------------------
84
// Constructor.
85
 
86
Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
87
{
88
    CYG_REPORT_FUNCTION();
89
 
90
    queue_map   = 0;
91
 
92
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
93
 
94
    pending_map = 0;
95
 
96
    for( int i = 0; i < CYGNUM_KERNEL_SCHED_PRIORITIES; i++ )
97
        pending[i] = 0;
98
 
99
#endif
100
 
101
    for( int i = 0; i < CYGNUM_KERNEL_CPU_MAX; i++ )
102
    {
103
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE        
104
        timeslice_count[i] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
105
#endif        
106
        need_reschedule[i] = true;
107
    }
108
 
109
    CYG_REPORT_RETURN();
110
}
111
 
112
// -------------------------------------------------------------------------
113
// Choose the best thread to run next
114
 
115
Cyg_Thread *
116
Cyg_Scheduler_Implementation::schedule(void)
117
{
118
    CYG_REPORT_FUNCTYPE("returning thread %08x");
119
 
120
    // The run queue may _never_ be empty, there is always
121
    // an idle thread at the lowest priority.
122
 
123
    CYG_ASSERT( queue_map != 0, "Run queue empty");
124
    CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
125
    CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
126
 
127
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
128
 
129
    Cyg_Thread *current = get_current_thread();
130
    register cyg_uint32 index;
131
 
132
    CYG_ASSERT( current->cpu != CYG_KERNEL_CPU_NONE, "Current thread does not have CPU set!");
133
 
134
    // If the current thread is still runnable, return it to pending
135
    // state so that it can be considered alongside any other threads
136
    // for execution.
137
    if( current->get_state() == Cyg_Thread::RUNNING )
138
    {
139
        current->cpu = CYG_KERNEL_CPU_NONE;
140
        pending[current->priority]++;
141
        pending_map |= (1<<current->priority);
142
    }
143
    else
144
    {
145
        // Otherwise, ensure that the thread is no longer marked as
146
        // running.
147
        current->cpu = CYG_KERNEL_CPU_NONE;
148
    }
149
 
150
 
151
    HAL_LSBIT_INDEX(index, pending_map);
152
 
153
    Cyg_RunQueue *queue = &run_queue[index];
154
 
155
    CYG_ASSERT( !queue->empty(), "Queue for index empty");
156
    CYG_ASSERT( pending[index] > 0, "Pending array and map disagree");
157
 
158
    Cyg_Thread *thread = queue->get_head();
159
 
160
    // We know there is a runnable thread in this queue, If the thread
161
    // we got is not it, scan until we find it. While not constant time,
162
    // this search has an upper bound of the number of CPUs in the system.
163
 
164
    while( thread->cpu != CYG_KERNEL_CPU_NONE )
165
        thread = thread->get_next();
166
 
167
    // Take newly scheduled thread out of pending map
168
    thread->cpu = CYG_KERNEL_CPU_THIS();
169
    if( --pending[index] == 0 )
170
        pending_map &= ~(1<<index);
171
 
172
#else    
173
 
174
    register cyg_uint32 index;
175
 
176
    HAL_LSBIT_INDEX(index, queue_map);
177
 
178
    Cyg_RunQueue *queue = &run_queue[index];
179
 
180
    CYG_ASSERT( !queue->empty(), "Queue for index empty");
181
 
182
    Cyg_Thread *thread = queue->get_head();
183
 
184
#endif
185
 
186
    CYG_INSTRUMENT_MLQ( SCHEDULE, thread, index);
187
 
188
    CYG_ASSERT( thread != NULL , "No threads in run queue");
189
    CYG_ASSERT( thread->queue == NULL , "Runnable thread on a queue!");
190
 
191
    CYG_REPORT_RETVAL(thread);
192
 
193
    return thread;
194
}
195
 
196
// -------------------------------------------------------------------------
197
 
198
void
199
Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
200
{
201
    CYG_REPORT_FUNCTION();
202
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
203
 
204
    cyg_priority pri                               = thread->priority;
205
    Cyg_RunQueue *queue = &run_queue[pri];
206
 
207
    CYG_INSTRUMENT_MLQ( ADD, thread, pri);
208
 
209
    CYG_ASSERT((CYG_THREAD_MIN_PRIORITY >= pri)
210
               && (CYG_THREAD_MAX_PRIORITY <= pri),
211
               "Priority out of range!");
212
 
213
    CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
214
 
215
    // If the thread is on some other queue, remove it
216
    // here.
217
    if( thread->queue != NULL )
218
    {
219
        thread->queue->remove(thread);
220
    }
221
 
222
    if( queue->empty() )
223
    {
224
        // set the map bit and ask for a reschedule if this is a
225
        // new highest priority thread.
226
 
227
        queue_map |= (1<<pri);
228
 
229
    }
230
    // else the queue already has an occupant, queue behind him
231
 
232
    queue->add_tail(thread);
233
 
234
    // If the new thread is higher priority than any
235
    // current thread, request a reschedule.
236
 
237
    set_need_reschedule(thread);
238
 
239
    // Also reset the timeslice_count so that this thread gets a full
240
    // timeslice once it begins to run.
241
 
242
    thread->timeslice_reset();
243
 
244
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
245
 
246
    // If the thread is not currently running, increment the pending
247
    // count for the priority, and if necessary set the bit in the
248
    // pending map.
249
 
250
    if( thread->cpu == CYG_KERNEL_CPU_NONE )
251
    {
252
        if( pending[pri]++ == 0 )
253
            pending_map |= (1<<pri);
254
    }
255
    // Otherwise the pending count will be dealt with in schedule().
256
 
257
#endif    
258
 
259
    CYG_ASSERT( thread->queue == NULL , "Runnable thread on a queue!");
260
    CYG_ASSERT( queue_map != 0, "Run queue empty");
261
    CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
262
    CYG_ASSERT( !run_queue[pri].empty(), "Queue for pri empty");
263
    CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
264
    CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
265
    CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
266
 
267
    CYG_REPORT_RETURN();
268
}
269
 
270
// -------------------------------------------------------------------------
271
 
272
void
273
Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
274
{
275
    CYG_REPORT_FUNCTION();
276
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
277
 
278
    CYG_ASSERT( queue_map != 0, "Run queue empty");
279
 
280
    cyg_priority pri    = thread->priority;
281
    Cyg_RunQueue *queue = &run_queue[pri];
282
 
283
    CYG_INSTRUMENT_MLQ( REM, thread, pri);
284
 
285
    CYG_ASSERT( pri != CYG_THREAD_MIN_PRIORITY, "Idle thread trying to sleep!");
286
    CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
287
 
288
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
289
 
290
    if( thread->cpu == CYG_KERNEL_CPU_NONE )
291
    {
292
        // If the thread is not running, then we need to adjust the
293
        // pending count array and map if necessary.
294
 
295
        if( --pending[pri] == 0 )
296
            pending_map &= ~(1<<pri);
297
    }
298
    else
299
    {
300
        // If the target thread is currently running on a different
301
        // CPU, send a reschedule interrupt there to deschedule it.        
302
        if( thread->cpu != CYG_KERNEL_CPU_THIS() )
303
            CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( thread->cpu, 0 );
304
    }
305
    // If the thread is current running on this CPU, then the pending
306
    // count will be dealt with in schedule().
307
 
308
#endif
309
 
310
    CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
311
    CYG_ASSERT( !run_queue[pri].empty(), "Queue for pri empty");
312
 
313
    // remove thread from queue
314
    queue->remove(thread);
315
 
316
    if( queue->empty() )
317
    {
318
        // If this was only thread in
319
        // queue, clear map.
320
 
321
        queue_map &= ~(1<<pri);
322
    }
323
 
324
    CYG_ASSERT( queue_map != 0, "Run queue empty");
325
    CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
326
    CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
327
    CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
328
 
329
    CYG_REPORT_RETURN();
330
}
331
 
332
// -------------------------------------------------------------------------
333
// Set the need_reschedule flag
334
// This function overrides the definition in Cyg_Scheduler_Base and tests
335
// for a reschedule condition based on the priorities of the given thread
336
// and the current thread(s).
337
 
338
void Cyg_Scheduler_Implementation::set_need_reschedule(Cyg_Thread *thread)
339
{
340
#ifndef CYGPKG_KERNEL_SMP_SUPPORT
341
 
342
    if( current_thread[0]->priority > thread->priority ||
343
        current_thread[0]->get_state() != Cyg_Thread::RUNNING )
344
        need_reschedule[0] = true;
345
 
346
#else
347
 
348
    HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
349
    HAL_SMP_CPU_TYPE cpu_count = CYG_KERNEL_CPU_COUNT();
350
 
351
    // Start with current CPU. If we can do the job locally then
352
    // that is most efficient. Only go on to other CPUs if that is
353
    // not possible.
354
 
355
    for(int i = 0; i < cpu_count; i++)
356
    {
357
        HAL_SMP_CPU_TYPE cpu = (i + cpu_this) % cpu_count;
358
 
359
        // If a CPU is not already marked for rescheduling, and its
360
        // current thread is of lower priority than _thread_, then
361
        // set its need_reschedule flag.
362
 
363
        Cyg_Thread *cur = current_thread[cpu];
364
 
365
        if( (!need_reschedule[cpu]) &&
366
            (cur->priority > thread->priority)
367
          )
368
        {
369
            need_reschedule[cpu] = true;
370
 
371
            if( cpu != cpu_this )
372
            {
373
                // All processors other than this one need to be sent
374
                // a reschedule interrupt.
375
 
376
                CYG_INSTRUMENT_SMP( RESCHED_SEND, cpu, 0 );
377
                CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( cpu, 0 );
378
            }
379
 
380
            // Having notionally rescheduled _thread_ onto the cpu, we
381
            // now see if we can reschedule the former current thread of
382
            // that CPU onto another.
383
 
384
            thread = cur;
385
        }
386
    }
387
 
388
#endif  
389
}
390
 
391
// -------------------------------------------------------------------------
392
// Set up initial idle thread
393
 
394
void Cyg_Scheduler_Implementation::set_idle_thread( Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu )
395
{
396
    // Make the thread the current thread for this CPU.
397
 
398
    current_thread[cpu] = thread;
399
 
400
    // This will insert the thread in the run queues and make it
401
    // available to execute.
402
    thread->resume();
403
 
404
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
405
 
406
    thread->cpu = cpu;
407
 
408
    // In SMP, we need to take this thread out of the pending array
409
    // and map.
410
 
411
    cyg_priority pri    = thread->priority;
412
    if( --pending[pri] == 0 )
413
        pending_map &= ~(1<<pri);
414
#endif    
415
 
416
}
417
 
418
// -------------------------------------------------------------------------
419
// register thread with scheduler
420
 
421
void
422
Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
423
{
424
    CYG_REPORT_FUNCTION();
425
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
426
    // No registration necessary in this scheduler
427
    CYG_REPORT_RETURN();
428
}
429
 
430
// -------------------------------------------------------------------------
431
 
432
// deregister thread
433
void
434
Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
435
{
436
    CYG_REPORT_FUNCTION();
437
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
438
    // No registration necessary in this scheduler    
439
    CYG_REPORT_RETURN();
440
}
441
 
442
// -------------------------------------------------------------------------
443
// Test the given priority for uniqueness
444
 
445
cyg_bool
446
Cyg_Scheduler_Implementation::unique( cyg_priority priority)
447
{
448
    CYG_REPORT_FUNCTYPE("returning %d");
449
    CYG_REPORT_FUNCARG1("priority=%d", priority);
450
    // Priorities are not unique
451
    CYG_REPORT_RETVAL(true);
452
    return true;
453
}
454
 
455
//==========================================================================
456
// Support for timeslicing option
457
 
458
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
459
 
460
// -------------------------------------------------------------------------
461
 
462
void
463
Cyg_Scheduler_Implementation::timeslice(void)
464
{
465
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
466
    CYG_REPORT_FUNCTION();
467
#endif
468
 
469
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
470
 
471
    HAL_SMP_CPU_TYPE cpu;
472
    HAL_SMP_CPU_TYPE cpu_count = CYG_KERNEL_CPU_COUNT();
473
    HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
474
 
475
    for( cpu = 0; cpu < cpu_count; cpu++ )
476
    {
477
        if( --timeslice_count[cpu] == 0 )
478
            if( cpu == cpu_this )
479
                timeslice_cpu();
480
            else CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( cpu, 0 );
481
    }
482
 
483
#else    
484
 
485
    if( --timeslice_count[CYG_KERNEL_CPU_THIS()] == 0 )
486
        timeslice_cpu();
487
 
488
#endif
489
 
490
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
491
    CYG_REPORT_RETURN();
492
#endif    
493
}
494
 
495
// -------------------------------------------------------------------------
496
 
497
void
498
Cyg_Scheduler_Implementation::timeslice_cpu(void)
499
{
500
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
501
    CYG_REPORT_FUNCTION();
502
#endif
503
 
504
    Cyg_Thread *thread = get_current_thread();
505
    HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
506
 
507
    CYG_ASSERT( queue_map != 0, "Run queue empty");
508
    CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
509
 
510
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
511
    if( thread->timeslice_enabled &&
512
        timeslice_count[cpu_this] == 0 )
513
#else    
514
    if( timeslice_count[cpu_this] == 0 )
515
#endif
516
    {
517
        CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
518
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
519
        CYG_TRACE0( true, "quantum consumed, time to reschedule" );
520
#endif
521
 
522
        CYG_ASSERT( get_sched_lock() > 0 , "Timeslice called with zero sched_lock");
523
 
524
        // Only try to rotate the run queue if the current thread is running.
525
        // Otherwise we are going to reschedule anyway.
526
        if( thread->get_state() == Cyg_Thread::RUNNING )
527
        {
528
            Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
529
 
530
            CYG_INSTRUMENT_MLQ( TIMESLICE, thread, 0);
531
 
532
            CYG_ASSERTCLASS( thread, "Bad current thread");
533
            CYG_ASSERTCLASS( sched, "Bad scheduler");
534
 
535
            cyg_priority pri    = thread->priority;
536
            Cyg_RunQueue *queue = &sched->run_queue[pri];
537
 
538
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
539
 
540
            // In SMP systems we set the head of the queue to point to
541
            // the thread immediately after the current
542
            // thread. schedule() will then pick that thread, or one
543
            // after it to run next.
544
 
545
            queue->to_head( thread->get_next() );
546
#else            
547
            queue->rotate();
548
#endif
549
 
550
            if( queue->get_head() != thread )
551
                sched->set_need_reschedule();
552
 
553
            timeslice_count[cpu_this] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
554
        }
555
    }
556
 
557
 
558
    CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
559
    CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
560
#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
561
    CYG_REPORT_RETURN();
562
#endif
563
}
564
 
565
// -------------------------------------------------------------------------
566
 
567
__externC void cyg_scheduler_timeslice_cpu(void)
568
{
569
    Cyg_Scheduler::scheduler.timeslice_cpu();
570
}
571
 
572
#endif
573
 
574
//==========================================================================
575
// Cyg_SchedThread_Implementation class members
576
 
577
Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
578
(
579
    CYG_ADDRWORD sched_info
580
)
581
{
582
    CYG_REPORT_FUNCTION();
583
    CYG_REPORT_FUNCARG1("sched_info=%08x", sched_info);
584
 
585
    // Set priority to the supplied value.
586
    priority = (cyg_priority)sched_info;
587
 
588
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
589
    // If timeslice_enabled exists, set it true by default
590
    timeslice_enabled = true;
591
#endif
592
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
593
    cpu = CYG_KERNEL_CPU_NONE;
594
#endif
595
 
596
    CYG_REPORT_RETURN();
597
}
598
 
599
// -------------------------------------------------------------------------
600
// Yield the processor to another thread
601
 
602
void
603
Cyg_SchedThread_Implementation::yield(void)
604
{
605
    CYG_REPORT_FUNCTION();
606
 
607
    // Prevent preemption
608
    Cyg_Scheduler::lock();
609
 
610
    Cyg_Thread *thread  = CYG_CLASSFROMBASE(Cyg_Thread,
611
                                            Cyg_SchedThread_Implementation,
612
                                            this);
613
 
614
    // Only do this if this thread is running. If it is not, there
615
    // is no point.
616
 
617
    if( thread->get_state() == Cyg_Thread::RUNNING )
618
    {
619
        // To yield we simply rotate the appropriate
620
        // run queue to the next thread and reschedule.
621
 
622
        CYG_INSTRUMENT_MLQ( YIELD, thread, 0);
623
 
624
        CYG_ASSERTCLASS( thread, "Bad current thread");
625
 
626
        Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
627
 
628
        CYG_ASSERTCLASS( sched, "Bad scheduler");
629
 
630
        cyg_priority pri    = thread->priority;
631
        Cyg_RunQueue *queue = &sched->run_queue[pri];
632
 
633
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
634
 
635
            // In SMP systems we set the head of the queue to point to
636
            // the thread immediately after the current
637
            // thread. schedule() will then pick that thread, or one
638
            // after it to run next.
639
 
640
            queue->to_head( thread->get_next() );
641
#else            
642
            queue->rotate();
643
#endif
644
 
645
        if( queue->get_head() != thread )
646
            sched->set_need_reschedule();
647
        else
648
        {
649
            // Reset the timeslice counter so that this thread gets a
650
            // full quantum as a reward for yielding when it is
651
            // eventually rescheduled.
652
            thread->timeslice_reset();
653
        }
654
 
655
    }
656
 
657
    // Unlock the scheduler and switch threads
658
#ifdef CYGDBG_USE_ASSERTS
659
    // This test keeps the assertions in unlock_inner() happy if
660
    // need_reschedule was not set above.
661
    if( !Cyg_Scheduler::get_need_reschedule() )
662
        Cyg_Scheduler::unlock();
663
    else
664
#endif    
665
    Cyg_Scheduler::unlock_reschedule();
666
 
667
 
668
    CYG_REPORT_RETURN();
669
}
670
 
671
// -------------------------------------------------------------------------
672
// Rotate the run queue at a specified priority.
673
// (pri is the decider, not this, so the routine is static)
674
 
675
void
676
Cyg_SchedThread_Implementation::rotate_queue( cyg_priority pri )
677
{
678
    CYG_REPORT_FUNCTION();
679
    CYG_REPORT_FUNCARG1("priority=%d", pri);
680
 
681
    // Prevent preemption
682
    Cyg_Scheduler::lock();
683
 
684
    Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
685
 
686
    CYG_ASSERTCLASS( sched, "Bad scheduler");
687
 
688
    Cyg_RunQueue *queue = &sched->run_queue[pri];
689
 
690
    if ( !queue->empty() ) {
691
        queue->rotate();
692
        sched->set_need_reschedule();
693
    }
694
 
695
    // Unlock the scheduler and switch threads
696
    Cyg_Scheduler::unlock();
697
 
698
    CYG_REPORT_RETURN();
699
}
700
 
701
// -------------------------------------------------------------------------
702
// Move this thread to the head of its queue
703
// (not necessarily a scheduler queue)
704
 
705
void
706
Cyg_SchedThread_Implementation::to_queue_head( void )
707
{
708
    CYG_REPORT_FUNCTION();
709
 
710
    // Prevent preemption
711
    Cyg_Scheduler::lock();
712
 
713
    Cyg_Thread *thread  = CYG_CLASSFROMBASE(Cyg_Thread,
714
                                            Cyg_SchedThread_Implementation,
715
                                            this);
716
 
717
    CYG_ASSERTCLASS( thread, "Bad current thread");
718
 
719
    Cyg_ThreadQueue *q = thread->get_current_queue();
720
    if( q != NULL )
721
        q->to_head( thread );
722
    else if( thread->in_list() )
723
    {
724
        // If the queue pointer is NULL then it is on a run
725
        // queue. Move the thread to the head of it's priority list
726
        // and force a reschedule.
727
 
728
        Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
729
        sched->run_queue[thread->priority].to_head( thread );
730
        sched->set_need_reschedule( thread );
731
    }
732
 
733
    // Unlock the scheduler and switch threads
734
    Cyg_Scheduler::unlock();
735
 
736
    CYG_REPORT_RETURN();
737
}
738
 
739
//==========================================================================
740
// Cyg_ThreadQueue_Implementation class members
741
 
742
// -------------------------------------------------------------------------        
743
 
744
void
745
Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
746
{
747
    CYG_REPORT_FUNCTION();
748
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
749
 
750
    CYG_INSTRUMENT_MLQ( ENQUEUE, this, thread );
751
 
752
#ifdef CYGIMP_KERNEL_SCHED_SORTED_QUEUES
753
 
754
    // Insert the thread into the queue in priority order.
755
 
756
    Cyg_Thread *qhead = get_head();
757
 
758
    if( qhead == NULL ) add_tail( thread );
759
    else if( qhead == qhead->get_next() )
760
    {
761
        // There is currently only one thread in the queue, join it
762
        // and adjust the queue pointer to point to the highest
763
        // priority of the two. If they are the same priority,
764
        // leave the pointer pointing to the oldest.
765
 
766
        qhead->insert( thread );
767
 
768
        if( thread->priority < qhead->priority )
769
            to_head(thread);
770
    }
771
    else
772
    {
773
        // There is more than one thread in the queue. First check
774
        // whether we are of higher priority than the head and if
775
        // so just jump in at the front. Also check whether we are
776
        // lower priority than the tail and jump onto the end.
777
        // Otherwise we really have to search the queue to find
778
        // our place.
779
 
780
        if( thread->priority < qhead->priority )
781
        {
782
            qhead->insert( thread );
783
            to_head(thread);
784
        }
785
        else if( thread->priority > get_tail()->priority )
786
        {
787
            // We are lower priority than any thread in the queue,
788
            // go in at the end.
789
 
790
            add_tail( thread );
791
        }
792
        else
793
        {
794
            // Search the queue. We do this backwards so that we
795
            // always add new threads after any that have the same
796
            // priority.
797
 
798
            // Because of the previous tests we know that this
799
            // search will terminate before we hit the head of the
800
            // queue, hence we do not need to check for that
801
            // condition.
802
 
803
            Cyg_Thread *qtmp = get_tail();
804
 
805
            // Scan the queue until we find a higher or equal
806
            // priority thread.
807
 
808
            while( qtmp->priority > thread->priority )
809
                qtmp = qtmp->get_prev();
810
 
811
            // Append ourself after the node pointed to by qtmp.
812
 
813
            qtmp->append( thread );
814
        }
815
    }
816
#else
817
    // Just add the thread to the tail of the list
818
    add_tail( thread );
819
#endif
820
 
821
    thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
822
                                      Cyg_ThreadQueue_Implementation,
823
                                      this);
824
    CYG_REPORT_RETURN();
825
}
826
 
827
// -------------------------------------------------------------------------
828
 
829
Cyg_Thread *
830
Cyg_ThreadQueue_Implementation::dequeue(void)
831
{
832
    CYG_REPORT_FUNCTYPE("returning thread %08x");
833
 
834
    Cyg_Thread *thread = rem_head();
835
 
836
    CYG_INSTRUMENT_MLQ( DEQUEUE, this, thread );
837
 
838
    if( thread != NULL )
839
        thread->queue = NULL;
840
 
841
    CYG_REPORT_RETVAL(thread);
842
    return thread;
843
}
844
 
845
// -------------------------------------------------------------------------
846
 
847
void
848
Cyg_ThreadQueue_Implementation::remove( Cyg_Thread *thread )
849
{
850
    CYG_REPORT_FUNCTION();
851
    CYG_REPORT_FUNCARG1("thread=%08x", thread);
852
 
853
    CYG_INSTRUMENT_MLQ( REMOVE, this, thread );
854
 
855
    thread->queue = NULL;
856
 
857
    Cyg_CList_T<Cyg_Thread>::remove( thread );
858
 
859
    CYG_REPORT_RETURN();
860
}
861
 
862
// -------------------------------------------------------------------------
863
 
864
Cyg_Thread *
865
Cyg_ThreadQueue_Implementation::highpri(void)
866
{
867
    CYG_REPORT_FUNCTYPE("returning thread %08x");
868
    CYG_REPORT_RETVAL(get_head());
869
    return get_head();
870
}
871
 
872
// -------------------------------------------------------------------------
873
 
874
inline void
875
Cyg_ThreadQueue_Implementation::set_thread_queue(Cyg_Thread *thread,
876
                                                 Cyg_ThreadQueue *tq )
877
 
878
{
879
    thread->queue = tq;
880
}
881
 
882
// -------------------------------------------------------------------------
883
 
884
#endif
885
 
886
// -------------------------------------------------------------------------
887
// EOF sched/mlqueue.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.