diff 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
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/src/sched/lottery.cxx
@@ -0,0 +1,445 @@
+//==========================================================================
+//
+//	sched/lottery.cxx
+//
+//	Lottery scheduler class implementation
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): 	nickg
+// Contributors:	nickg
+// Date:	1997-09-16
+// Purpose:	Lottery scheduler class implementation
+// Description:	This file contains the implementations of
+//              Cyg_Scheduler_Implementation and
+//              Cyg_SchedThread_Implementation.
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <cyg/kernel/sched.hxx>        // our header
+#include <cyg/kernel/intr.hxx>         // interrupt defines, for Cyg_HAL_Clock
+
+#include <cyg/hal/hal_arch.h>          // Architecture specific definitions
+
+
+#include <cyg/kernel/thread.inl>       // thread inlines
+#include <cyg/kernel/sched.inl>        // scheduler inlines
+
+#ifdef CYGSEM_KERNEL_SCHED_LOTTERY
+
+#define CYG_ENABLE_TRACE 1
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class static members
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+cyg_count32 Cyg_Scheduler_Implementation::timeslice_count =
+                                        CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+
+#endif
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class members
+
+// -------------------------------------------------------------------------
+// Constructor.
+
+Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
+{
+    CYG_REPORT_FUNCTION();
+
+    total_tickets = 0;
+    rand_seed = 1;
+}
+
+// -------------------------------------------------------------------------
+// Choose the best thread to run next
+
+Cyg_Thread *Cyg_Scheduler_Implementation::schedule()
+{
+    CYG_REPORT_FUNCTION();
+
+#ifdef CYG_HAL_POWERPC
+
+    // PowerPc specific version of random number generator.
+    register cyg_int32 r1 asm("r4");
+    r1 = rand_seed;
+    asm(
+        "li     7,0;"
+        "ori    7,7,33614;"
+        "mulhwu 5,7,%0;"
+        "mullw  6,7,%0;"
+        "srawi  6,6,1;"
+        "add    %0,5,6;"
+        "cmpwi  %0,0;"
+        "bge    1f;"
+        "slwi   %0,%0,1;"
+        "srwi   %0,%0,1;"
+        "addi   %0,%0,1;"
+        "1:;"
+        : "=r"(r1)
+        : "0"(r1)
+        : "r5", "r6", "r7"
+        );
+    rand_seed = r1;    
+
+#else
+#if 1
+    rand_seed = (rand_seed * 1103515245) + 1234;
+    cyg_int32 r1 = rand_seed & 0x7FFFFFFF;
+#else    
+    // Generic implementation of RNG.
+#if( CYG_BYTEORDER == CYG_MSBFIRST )
+#define _LO 1    
+#define _HI 0
+#else
+#define _LO 0    
+#define _HI 1
+#endif    
+    union { cyg_int64 r64; cyg_int32 r32[2]; } u;
+    u.r64 = (cyg_int64)rand_seed * 33614LL;
+    cyg_int32 r1 = u.r32[_HI] + (u.r32[_LO]>>1);
+    if( r1 < 0 )
+        r1 = (r1 & 0x7FFFFFFF) + 1;
+    rand_seed = r1;
+#undef _LO
+#undef _HI
+#endif    
+#endif    
+
+    cyg_int32 ticket = r1 % total_tickets;
+    cyg_int32 tick = ticket;
+    Cyg_Thread *thread = run_queue.highpri();
+
+    // Search the run queue for the thread with the
+    // given ticket.
+    while( ticket > 0 )
+    {
+        ticket -= thread->priority;
+        if( ticket <= 0 ) break;
+        thread = thread->next;
+        
+        CYG_ASSERT( thread != run_queue.highpri(), "Looping in scheduler");
+    }
+
+    CYG_TRACE3( CYG_ENABLE_TRACE,
+	"seed %08x ticket %d thread %08x",
+        rand_seed, tick, thread);
+
+    // If the thread has any compensation tickets, take them away since
+    // it has just won.
+
+    if( thread->compensation_tickets > 0 )
+    {
+        thread->priority -= thread->compensation_tickets;
+        total_tickets -= thread->compensation_tickets;
+        thread->compensation_tickets = 0;
+    }
+ 
+    // Re-insert thread at head of list. This reduces runtime by
+    // putting the large ticket holders at the front of the list.
+    
+//    run_queue.remove(thread);
+//    run_queue.enqueue(thread);
+
+    CYG_CHECK_DATA_PTR( thread, "Invalid next thread pointer");            
+    CYG_ASSERTCLASS( thread, "Bad next thread" );
+    
+    return thread;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+
+    // If the thread is on some other queue, remove it
+    // here.
+    if( thread->queue != NULL )
+    {
+        thread->queue->remove(thread);
+        thread->queue = NULL;
+    }
+    
+    total_tickets += thread->priority;
+
+    run_queue.enqueue(thread);
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+
+    run_queue.remove(thread);
+
+    total_tickets -= thread->priority;
+
+    // Compensate the thread for the segment of the quantum that
+    // it used. This makes it more likely to win the lottery next time
+    // it is scheduled. We only do this for threads that have voluntarily
+    // given up the CPU.
+
+//    if( thread->get_state() != Cyg_Thread::RUNNING )
+    {
+#if 0        
+        cyg_uint32 hal_ticks;
+        HAL_CLOCK_READ( &hal_ticks );
+        thread->compensation_tickets = thread->priority *
+            CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / hal_ticks;
+#else
+        thread->compensation_tickets = (thread->priority *
+            CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS) / timeslice_count;
+        
+#endif        
+        thread->priority += thread->compensation_tickets;
+    }
+}
+
+// -------------------------------------------------------------------------
+// register thread with scheduler
+
+void Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+        
+    // No registration necessary in this scheduler
+}
+
+// -------------------------------------------------------------------------
+
+// deregister thread
+void Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+        
+    // No registration necessary in this scheduler    
+}
+    
+// -------------------------------------------------------------------------
+// Test the given priority for uniqueness
+
+cyg_bool Cyg_Scheduler_Implementation::unique( cyg_priority priority)
+{
+    CYG_REPORT_FUNCTION();
+        
+    // Priorities are not unique
+    return true;
+}
+
+//==========================================================================
+// Support for timeslicing option
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+void Cyg_Scheduler_Implementation::timeslice()
+{
+    CYG_REPORT_FUNCTION();
+
+    if( --timeslice_count <= 0 )
+    {
+        CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
+        
+        // Force a reschedule on each timeslice
+        need_reschedule = true;
+        timeslice_count = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+    }
+}
+
+#endif
+
+//==========================================================================
+// Cyg_Cyg_SchedThread_Implementation class members
+
+Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
+(
+    CYG_ADDRWORD sched_info
+)
+{
+    CYG_REPORT_FUNCTION();
+
+    priority = cyg_priority(sched_info);
+    
+    // point the next and prev field at this thread.
+    
+    next = prev = CYG_CLASSFROMBASE(Cyg_Thread,
+                                    Cyg_SchedThread_Implementation,
+                                    this);
+}
+
+// -------------------------------------------------------------------------
+// Insert thread in front of this
+
+void Cyg_SchedThread_Implementation::insert( Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+        
+    thread->next        = CYG_CLASSFROMBASE(Cyg_Thread,
+                                            Cyg_SchedThread_Implementation,
+                                            this);
+    thread->prev        = prev;
+    prev->next          = thread;
+    prev                = thread;    
+}
+
+// -------------------------------------------------------------------------
+// remove this from queue
+
+void Cyg_SchedThread_Implementation::remove()
+{
+    CYG_REPORT_FUNCTION();
+        
+    next->prev          = prev;
+    prev->next          = next;
+    next = prev         = CYG_CLASSFROMBASE(Cyg_Thread,
+                                            Cyg_SchedThread_Implementation,
+                                            this);
+}
+
+// -------------------------------------------------------------------------
+// Yield the processor to another thread
+
+void Cyg_SchedThread_Implementation::yield()
+{
+    CYG_REPORT_FUNCTION();
+        
+
+}
+
+//==========================================================================
+// Cyg_ThreadQueue_Implementation class members
+
+void Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+
+    // Always put thread at head of queue
+    if( queue == NULL ) queue = thread;
+    else
+    {
+        queue->insert(thread);
+//        queue->next->insert(thread);
+//        queue = thread;
+    }
+    
+    thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
+                                      Cyg_ThreadQueue_Implementation,
+                                      this);    
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::dequeue()
+{
+    CYG_REPORT_FUNCTION();
+        
+    if( queue == NULL ) return NULL;
+    
+    Cyg_Thread *thread = queue;
+    
+    if( thread->next == thread )
+    {
+        // sole thread on list, NULL out ptr
+        queue = NULL;
+    }
+    else
+    {
+        // advance to next and remove thread
+        queue = thread->next;
+        thread->remove();
+    }
+
+    thread->queue = NULL;
+
+    return thread;
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::highpri()
+{
+    CYG_REPORT_FUNCTION();
+        
+    return queue;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_ThreadQueue_Implementation::remove(Cyg_Thread *thread)
+{
+    CYG_REPORT_FUNCTION();
+        
+    // If the thread we want is the at the head
+    // of the list, and is on its own, clear the
+    // list and return. Otherwise advance to the
+    // next thread and remove ours. If the thread
+    // is not at the head of the list, just dequeue
+    // it.
+
+    thread->queue = NULL;
+    
+    if( queue == thread )
+    {
+        if( thread->next == thread )
+        {
+            queue = NULL;
+            return;
+        }
+        else queue = thread->next;
+    }
+
+    thread->Cyg_SchedThread_Implementation::remove();
+
+}
+
+// -------------------------------------------------------------------------
+// Rotate the front thread on the queue to the back.
+
+void Cyg_ThreadQueue_Implementation::rotate()
+{
+    CYG_REPORT_FUNCTION();
+        
+    queue = queue->next;
+}
+
+// -------------------------------------------------------------------------
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF sched/lottery.cxx