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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      sched/sched.cxx
4
//
5
//      Scheduler class implementations
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:        nickg
44
// Date:        1997-09-15
45
// Purpose:     Scheduler class implementation
46
// Description: This file contains the definitions of the scheduler class
47
//              member functions that are common to all scheduler
48
//              implementations.
49
//
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
#include <pkgconf/kernel.h>
55
 
56
#include <cyg/kernel/ktypes.h>         // base kernel types
57
#include <cyg/infra/cyg_trac.h>        // tracing macros
58
#include <cyg/infra/cyg_ass.h>         // assertion macros
59
#include <cyg/kernel/instrmnt.h>       // instrumentation
60
 
61
#include <cyg/kernel/sched.hxx>        // our header
62
 
63
#include <cyg/kernel/thread.hxx>       // thread classes
64
#include <cyg/kernel/intr.hxx>         // Interrupt interface
65
 
66
#include <cyg/hal/hal_arch.h>          // Architecture specific definitions
67
 
68
#include <cyg/kernel/thread.inl>       // thread inlines
69
#include <cyg/kernel/sched.inl>        // scheduler inlines
70
 
71
//-------------------------------------------------------------------------
72
// Some local tracing control - a default.
73
#ifdef CYGDBG_USE_TRACING
74
# if !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_SIMPLE ) && \
75
     !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_FANCY  )
76
   // ie. not a tracing implementation that takes a long time to output
77
 
78
#  ifndef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
79
#   define CYGDBG_KERNEL_TRACE_UNLOCK_INNER
80
#  endif // control not already defined
81
 
82
# endif  // trace implementation not ..._SIMPLE && not ..._FANCY
83
#endif   // CYGDBG_USE_TRACING
84
 
85
// -------------------------------------------------------------------------
86
// Static Cyg_Scheduler class members
87
 
88
// We start with sched_lock at 1 so that any kernel code we
89
// call during initialization will not try to reschedule.
90
 
91
CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS;
92
 
93
Cyg_Thread              *volatile Cyg_Scheduler_Base::current_thread[CYGNUM_KERNEL_CPU_MAX];
94
 
95
volatile cyg_bool       Cyg_Scheduler_Base::need_reschedule[CYGNUM_KERNEL_CPU_MAX];
96
 
97
Cyg_Scheduler           Cyg_Scheduler::scheduler CYG_INIT_PRIORITY( SCHEDULER );
98
 
99
volatile cyg_ucount32   Cyg_Scheduler_Base::thread_switches[CYGNUM_KERNEL_CPU_MAX];
100
 
101
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
102
 
103
CYG_BYTE cyg_sched_cpu_interrupt[CYGNUM_KERNEL_CPU_MAX][sizeof(Cyg_Interrupt)]
104
                                 CYGBLD_ANNOTATE_VARIABLE_SCHED;
105
 
106
__externC cyg_ISR cyg_hal_cpu_message_isr;
107
__externC cyg_DSR cyg_hal_cpu_message_dsr;
108
 
109
inline void *operator new(size_t size, void *ptr) { return ptr; };
110
 
111
#endif
112
 
113
// -------------------------------------------------------------------------
114
// Scheduler unlock function.
115
 
116
// This is only called when there is the potential for real work to be
117
// done. Other cases are handled in Cyg_Scheduler::unlock() which is
118
// an inline; _or_ this function may have been called from
119
// Cyg_Scheduler::reschedule(), or Cyg_Scheduler::unlock_reschedule. The
120
// new_lock argument contains the value that the scheduler lock should
121
// have after this function has completed. If it is zero then the lock is
122
// being released and some extra work (running ASRs, checking for DSRs) is
123
// done before returning. If it is non-zero then it must equal the
124
// current value of the lock, and is used to indicate that we want to
125
// reacquire the scheduler lock before returning. This latter option
126
// only makes any sense if the current thread is no longer runnable,
127
// e.g. sleeping, otherwise this function will do nothing.
128
// This approach of passing in the lock value at the end effectively
129
// makes the scheduler lock a form of per-thread variable. Each call
130
// to unlock_inner() carries with it the value the scheduler should
131
// have when it reschedules this thread back, and leaves this function.
132
// When it is non-zero, and the thread is rescheduled, no ASRS are run,
133
// or DSRs processed. By doing this, it makes it possible for threads
134
// that want to go to sleep to wake up with the scheduler lock in the
135
// same state it was in before.
136
 
137
void Cyg_Scheduler::unlock_inner( cyg_ucount32 new_lock )
138
{
139
#ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
140
    CYG_REPORT_FUNCTION();
141
#endif    
142
 
143
    do {
144
 
145
        CYG_PRECONDITION( new_lock==0 ? get_sched_lock() == 1 :
146
                          ((get_sched_lock() == new_lock) || (get_sched_lock() == new_lock+1)),
147
                          "sched_lock not at expected value" );
148
 
149
#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
150
 
151
        // Call any pending DSRs. Do this here to ensure that any
152
        // threads that get awakened are properly scheduled.
153
 
154
        if( new_lock == 0 && Cyg_Interrupt::DSRs_pending() )
155
            Cyg_Interrupt::call_pending_DSRs();
156
#endif
157
 
158
        Cyg_Thread *current = get_current_thread();
159
 
160
        CYG_ASSERTCLASS( current, "Bad current thread" );
161
 
162
#ifdef CYGFUN_KERNEL_ALL_THREADS_STACK_CHECKING
163
        // should have  CYGVAR_KERNEL_THREADS_LIST
164
        current = Cyg_Thread::get_list_head();
165
        while ( current ) {
166
            current->check_stack();
167
            current = current->get_list_next();
168
        }
169
        current = get_current_thread();
170
#endif
171
 
172
#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
173
        current->check_stack();
174
#endif
175
 
176
        // If the current thread is going to sleep, or someone
177
        // wants a reschedule, choose another thread to run
178
 
179
        if( current->state != Cyg_Thread::RUNNING || get_need_reschedule() ) {
180
 
181
            CYG_INSTRUMENT_SCHED(RESCHEDULE,0,0);
182
 
183
            // Get the next thread to run from scheduler
184
            Cyg_Thread *next = scheduler.schedule();
185
 
186
            CYG_CHECK_DATA_PTR( next, "Invalid next thread pointer");
187
            CYG_ASSERTCLASS( next, "Bad next thread" );
188
 
189
            if( current != next )
190
            {
191
 
192
                CYG_INSTRUMENT_THREAD(SWITCH,current,next);
193
 
194
                // Count this thread switch
195
                thread_switches[CYG_KERNEL_CPU_THIS()]++;
196
 
197
#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
198
                next->check_stack(); // before running it
199
#endif
200
                current->timeslice_save();
201
 
202
                // Switch contexts
203
                HAL_THREAD_SWITCH_CONTEXT( &current->stack_ptr,
204
                                           &next->stack_ptr );
205
 
206
                // Worry here about possible compiler
207
                // optimizations across the above call that may try to
208
                // propogate common subexpresions.  We would end up
209
                // with the expression from one thread in its
210
                // successor. This is only a worry if we do not save
211
                // and restore the complete register set. We need a
212
                // way of marking functions that return into a
213
                // different context. A temporary fix would be to
214
                // disable CSE (-fdisable-cse) in the compiler.
215
 
216
                // We return here only when the current thread is
217
                // rescheduled.  There is a bit of housekeeping to do
218
                // here before we are allowed to go on our way.
219
 
220
                CYG_CHECK_DATA_PTR( current, "Invalid current thread pointer");
221
                CYG_ASSERTCLASS( current, "Bad current thread" );
222
 
223
                current_thread[CYG_KERNEL_CPU_THIS()] = current;   // restore current thread pointer
224
 
225
                current->timeslice_restore();
226
            }
227
 
228
            clear_need_reschedule();    // finished rescheduling
229
        }
230
 
231
        if( new_lock == 0 )
232
        {
233
 
234
#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
235
 
236
            // Check whether the ASR is pending and not inhibited.  If
237
            // we can call it, then transfer this info to a local
238
            // variable (call_asr) and clear the pending flag.  Note
239
            // that we only do this if the scheduler lock is about to
240
            // be zeroed. In any other circumstance we are not
241
            // unlocking.
242
 
243
            cyg_bool call_asr = false;
244
 
245
            if( (current->asr_inhibit == 0) && current->asr_pending )
246
            {
247
                call_asr = true;
248
                current->asr_pending = false;
249
            }
250
#endif
251
 
252
            HAL_REORDER_BARRIER(); // Make sure everything above has happened
253
                                   // by this point
254
            zero_sched_lock();     // Clear the lock
255
            HAL_REORDER_BARRIER();
256
 
257
#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
258
 
259
            // Now check whether any DSRs got posted during the thread
260
            // switch and if so, go around again. Making this test after
261
            // the lock has been zeroed avoids a race condition in which
262
            // a DSR could have been posted during a reschedule, but would
263
            // not be run until the _next_ time we release the sched lock.
264
 
265
            if( Cyg_Interrupt::DSRs_pending() ) {
266
                inc_sched_lock();   // reclaim the lock
267
                continue;           // go back to head of loop
268
            }
269
 
270
#endif
271
            // Otherwise the lock is zero, we can return.
272
 
273
//            CYG_POSTCONDITION( get_sched_lock() == 0, "sched_lock not zero" );
274
 
275
#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
276
            // If the test within the sched_lock indicating that the ASR
277
            // be called was true, call it here. Calling the ASR must be
278
            // the very last thing we do here, since it must run as close
279
            // to "user" state as possible.
280
 
281
            if( call_asr ) current->asr(current->asr_data);
282
#endif
283
 
284
        }
285
        else
286
        {
287
            // If new_lock is non-zero then we restore the sched_lock to
288
            // the value given.
289
 
290
            HAL_REORDER_BARRIER();
291
 
292
            set_sched_lock(new_lock);
293
 
294
            HAL_REORDER_BARRIER();
295
        }
296
 
297
#ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
298
        CYG_REPORT_RETURN();
299
#endif
300
        return;
301
 
302
    } while( 1 );
303
 
304
    CYG_FAIL( "Should not be executed" );
305
}
306
 
307
// -------------------------------------------------------------------------
308
// Thread startup. This is called from Cyg_Thread::thread_entry() and
309
// performs some housekeeping for a newly started thread.
310
 
311
void Cyg_Scheduler::thread_entry( Cyg_Thread *thread )
312
{
313
    clear_need_reschedule();            // finished rescheduling
314
    set_current_thread(thread);         // restore current thread pointer
315
 
316
    CYG_INSTRUMENT_THREAD(ENTER,thread,0);
317
 
318
    thread->timeslice_reset();
319
    thread->timeslice_restore();
320
 
321
    // Finally unlock the scheduler. As well as clearing the scheduler
322
    // lock this allows any pending DSRs to execute. The new thread
323
    // must start with a lock of zero, so we keep unlocking until the
324
    // lock reaches zero.
325
    while( get_sched_lock() != 0 )
326
        unlock();
327
}
328
 
329
// -------------------------------------------------------------------------
330
// Start the scheduler. This is called after the initial threads have been
331
// created to start scheduling. It gets any other CPUs running, and then
332
// enters the scheduler.
333
 
334
void Cyg_Scheduler::start()
335
{
336
    CYG_REPORT_FUNCTION();
337
 
338
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
339
 
340
    HAL_SMP_CPU_TYPE cpu;
341
 
342
    for( cpu = 0; cpu < CYG_KERNEL_CPU_COUNT(); cpu++ )
343
    {
344
        // Don't start this CPU, it is running already!
345
        if( cpu == CYG_KERNEL_CPU_THIS() )
346
            continue;
347
 
348
        CYG_KERNEL_CPU_START( cpu );
349
    }
350
 
351
#endif    
352
 
353
    start_cpu();
354
}
355
 
356
// -------------------------------------------------------------------------
357
// Start scheduling on this CPU. This is called on each CPU in the system
358
// when it is started.
359
 
360
void Cyg_Scheduler::start_cpu()
361
{
362
    CYG_REPORT_FUNCTION();
363
 
364
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
365
 
366
    // Set up the inter-CPU interrupt for this CPU
367
 
368
    Cyg_Interrupt * intr = new( (void *)&cyg_sched_cpu_interrupt[HAL_SMP_CPU_THIS()] )
369
        Cyg_Interrupt( CYGNUM_HAL_SMP_CPU_INTERRUPT_VECTOR( HAL_SMP_CPU_THIS() ),
370
                       0,
371
                       0,
372
                       cyg_hal_cpu_message_isr,
373
                       cyg_hal_cpu_message_dsr
374
                     );
375
 
376
    intr->set_cpu( intr->get_vector(), HAL_SMP_CPU_THIS() );
377
 
378
    intr->attach();
379
 
380
    intr->unmask_interrupt( intr->get_vector() );
381
 
382
#endif    
383
 
384
    // Get the first thread to run from scheduler
385
    register Cyg_Thread *next = scheduler.schedule();
386
 
387
    CYG_ASSERTCLASS( next, "Bad initial thread" );
388
 
389
    clear_need_reschedule();            // finished rescheduling
390
    set_current_thread(next);           // restore current thread pointer
391
 
392
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
393
    // Reference the real time clock. This ensures that at least one
394
    // reference to the kernel_clock.o object exists, without which
395
    // the object will not be included while linking.
396
    CYG_REFERENCE_OBJECT( Cyg_Clock::real_time_clock );
397
#endif
398
 
399
    // Load the first thread. This will also enable interrupts since
400
    // the initial state of all threads is to have interrupts enabled.
401
 
402
    HAL_THREAD_LOAD_CONTEXT( &next->stack_ptr );
403
 
404
}
405
 
406
// -------------------------------------------------------------------------
407
// SMP support functions
408
 
409
#ifdef CYGPKG_KERNEL_SMP_SUPPORT
410
 
411
// This is called on each secondary CPU on its interrupt stack after
412
// the initial CPU has initialized the world.
413
 
414
externC void cyg_kernel_smp_startup()
415
{
416
    CYG_INSTRUMENT_SMP( CPU_START, CYG_KERNEL_CPU_THIS(), 0 );
417
    Cyg_Scheduler::lock();
418
    Cyg_Scheduler::start_cpu();
419
}
420
 
421
// This is called from the DSR of the inter-CPU interrupt to cause a
422
// reschedule when the scheduler lock is zeroed.
423
 
424
__externC void cyg_scheduler_set_need_reschedule()
425
{
426
    CYG_INSTRUMENT_SMP( RESCHED_RECV, 0, 0 );
427
    Cyg_Scheduler::need_reschedule[HAL_SMP_CPU_THIS()] = true;
428
}
429
 
430
#endif
431
 
432
// -------------------------------------------------------------------------
433
// Consistency checker
434
 
435
#ifdef CYGDBG_USE_ASSERTS
436
 
437
cyg_bool Cyg_Scheduler::check_this( cyg_assert_class_zeal zeal) const
438
{
439
    CYG_REPORT_FUNCTION();
440
 
441
    // check that we have a non-NULL pointer first
442
    if( this == NULL ) return false;
443
 
444
    switch( zeal )
445
    {
446
    case cyg_system_test:
447
    case cyg_extreme:
448
    case cyg_thorough:
449
        if( !get_current_thread()->check_this(zeal) ) return false;
450
    case cyg_quick:
451
    case cyg_trivial:
452
    case cyg_none:
453
    default:
454
        break;
455
    };
456
 
457
    return true;
458
}
459
 
460
#endif
461
 
462
//==========================================================================
463
// SchedThread members
464
 
465
// -------------------------------------------------------------------------
466
// Static data members
467
 
468
#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
469
 
470
# ifdef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
471
Cyg_ASR *Cyg_SchedThread::asr = &Cyg_SchedThread::asr_default;
472
# endif
473
 
474
# ifdef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
475
CYG_ADDRWORD Cyg_SchedThread::asr_data = 0;
476
# endif
477
 
478
#endif // CYGSEM_KERNEL_SCHED_ASR_SUPPORT
479
 
480
// -------------------------------------------------------------------------
481
// Constructor
482
 
483
Cyg_SchedThread::Cyg_SchedThread(Cyg_Thread *thread, CYG_ADDRWORD sched_info)
484
: Cyg_SchedThread_Implementation(sched_info)
485
{
486
    CYG_REPORT_FUNCTION();
487
 
488
    queue = NULL;
489
 
490
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
491
 
492
    mutex_count = 0;
493
 
494
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
495
 
496
    priority_inherited = false;
497
 
498
#endif
499
#endif
500
 
501
#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
502
 
503
    asr_inhibit = 0;
504
    asr_pending = false;
505
 
506
#ifndef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
507
    asr = asr_default;
508
#endif
509
#ifdef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
510
    asr_data = NULL
511
#endif        
512
 
513
#endif    
514
}
515
 
516
// -------------------------------------------------------------------------
517
// ASR support functions
518
 
519
#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
520
 
521
// -------------------------------------------------------------------------
522
// Set ASR
523
// Install a new ASR, returning the old one.
524
 
525
void Cyg_SchedThread::set_asr( Cyg_ASR  *new_asr, CYG_ADDRWORD  new_data,
526
                  Cyg_ASR **old_asr, CYG_ADDRWORD *old_data)
527
{
528
    CYG_REPORT_FUNCTION();
529
 
530
    // Do this with the scheduler locked...
531
    Cyg_Scheduler::lock();
532
 
533
    if( old_asr != NULL ) *old_asr = asr;
534
    if( old_data != NULL ) *old_data = asr_data;
535
 
536
    // If new_asr is NULL, do not change the ASR,
537
    // but only change the data.
538
    if( new_asr != NULL ) asr = new_asr;
539
    asr_data = new_data;
540
 
541
    Cyg_Scheduler::unlock();
542
}
543
 
544
// -------------------------------------------------------------------------
545
// Clear ASR
546
 
547
void Cyg_SchedThread::clear_asr()
548
{
549
    CYG_REPORT_FUNCTION();
550
 
551
    // Do this with the scheduler locked...
552
    Cyg_Scheduler::lock();
553
 
554
    // Reset ASR to default.
555
    asr = asr_default;
556
    asr_data = 0;
557
 
558
    Cyg_Scheduler::unlock();
559
}
560
 
561
// -------------------------------------------------------------------------
562
// Default ASR function.
563
// having this avoids our having to worry about ever seeing a NULL
564
// pointer as the ASR function.
565
 
566
void Cyg_SchedThread::asr_default(CYG_ADDRWORD data)
567
{
568
    CYG_REPORT_FUNCTION();
569
 
570
    data=data;
571
    return;
572
}
573
 
574
#endif
575
 
576
// -------------------------------------------------------------------------
577
// Generic priority protocol support
578
 
579
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
580
 
581
void Cyg_SchedThread::set_inherited_priority( cyg_priority pri, Cyg_Thread *thread )
582
{
583
    CYG_REPORT_FUNCTION();
584
 
585
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
586
 
587
    // This is the comon code for priority inheritance and ceiling
588
    // protocols. This implementation provides a simplified version of
589
    // the protocol.
590
 
591
    Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
592
                                         Cyg_SchedThread,
593
                                         this);
594
 
595
    CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
596
 
597
    // Compare with *current* priority in case thread has already
598
    // inherited - for relay case below.
599
    if( pri < priority )
600
    {
601
        cyg_priority mypri = priority;
602
        cyg_bool already_inherited = priority_inherited;
603
 
604
        // If this is first inheritance, copy the old pri
605
        // and set inherited flag. We clear it before setting the
606
        // pri since set_priority() is inheritance aware.
607
        // This is called with the sched locked, so no race conditions.
608
 
609
        priority_inherited = false;     // so that set_prio DTRT
610
 
611
        self->set_priority( pri );
612
 
613
        if( !already_inherited )
614
            original_priority = mypri;
615
 
616
        priority_inherited = true;      // regardless, because it is now
617
 
618
    }
619
 
620
#endif
621
}
622
 
623
void Cyg_SchedThread::relay_inherited_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue)
624
{
625
    CYG_REPORT_FUNCTION();
626
 
627
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
628
 
629
    // A simple implementation of priority inheritance.
630
    // At its simplest, this member does nothing.
631
 
632
    // If there is anyone else waiting, then the *new* owner inherits from
633
    // the current one, since that is a maxima of the others waiting.
634
    // (It's worth not doing if there's nobody waiting to prevent
635
    // unneccessary priority skew.)  This could be viewed as a discovered
636
    // priority ceiling.
637
 
638
    if ( !pqueue->empty() )
639
        set_inherited_priority( ex_owner->get_current_priority(), ex_owner );
640
 
641
#endif
642
}
643
 
644
void Cyg_SchedThread::clear_inherited_priority()
645
{
646
    CYG_REPORT_FUNCTION();
647
 
648
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
649
 
650
    // A simple implementation of priority inheritance/ceiling
651
    // protocols.  The simplification in this algorithm is that we do
652
    // not reduce our priority until we have freed all mutexes
653
    // claimed. Hence we can continue to run at an artificially high
654
    // priority even when we should not.  However, since nested
655
    // mutexes are rare, the thread we have inherited from is likely
656
    // to be locking the same mutexes we are, and mutex claim periods
657
    // should be very short, the performance difference between this
658
    // and a more complex algorithm should be negligible. The most
659
    // important advantage of this algorithm is that it is fast and
660
    // deterministic.
661
 
662
    Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
663
                                         Cyg_SchedThread,
664
                                         this);
665
 
666
    CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
667
 
668
    if( mutex_count == 0 && priority_inherited )
669
    {
670
        priority_inherited = false;
671
 
672
        // Only make an effort if the priority must change
673
        if( priority < original_priority )
674
            self->set_priority( original_priority );
675
 
676
    }
677
 
678
#endif        
679
}
680
 
681
#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
682
 
683
// -------------------------------------------------------------------------
684
// Priority inheritance support.
685
 
686
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
687
 
688
// -------------------------------------------------------------------------
689
// Inherit the priority of the provided thread if it
690
// has a higher priority than ours.
691
 
692
void Cyg_SchedThread::inherit_priority( Cyg_Thread *thread)
693
{
694
    CYG_REPORT_FUNCTION();
695
 
696
    Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
697
                                         Cyg_SchedThread,
698
                                         this);
699
 
700
    CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
701
    CYG_ASSERT( self != thread, "Trying to inherit from self!");
702
 
703
    self->set_inherited_priority( thread->get_current_priority(), thread );
704
 
705
}
706
 
707
// -------------------------------------------------------------------------
708
// Inherit the priority of the ex-owner thread or from the queue if it
709
// has a higher priority than ours.
710
 
711
void Cyg_SchedThread::relay_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue)
712
{
713
    CYG_REPORT_FUNCTION();
714
 
715
    relay_inherited_priority( ex_owner, pqueue );
716
}
717
 
718
// -------------------------------------------------------------------------
719
// Lose a priority inheritance
720
 
721
void Cyg_SchedThread::disinherit_priority()
722
{
723
    CYG_REPORT_FUNCTION();
724
 
725
    CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
726
 
727
    clear_inherited_priority();
728
}
729
 
730
#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
731
 
732
// -------------------------------------------------------------------------
733
// Priority ceiling support
734
 
735
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
736
 
737
void Cyg_SchedThread::set_priority_ceiling( cyg_priority pri )
738
{
739
    CYG_REPORT_FUNCTION();
740
 
741
    CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
742
 
743
    set_inherited_priority( pri );
744
 
745
}
746
 
747
void Cyg_SchedThread::clear_priority_ceiling( )
748
{
749
    CYG_REPORT_FUNCTION();
750
 
751
    CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
752
 
753
    clear_inherited_priority();
754
}
755
 
756
#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
757
 
758
// -------------------------------------------------------------------------
759
// EOF sched/sched.cxx

powered by: WebSVN 2.1.0

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