diff packages/kernel/current/src/sched/sched.cxx @ 177:4c750ce71ae3

Merge from eCos master repository on 2001-08-10-19:22:57-BST
author jlarmour
date Fri, 10 Aug 2001 19:27:55 +0000
parents 42f843b391aa
children e0c0827131d1
line wrap: on
line diff
--- a/packages/kernel/current/src/sched/sched.cxx
+++ b/packages/kernel/current/src/sched/sched.cxx
@@ -80,15 +80,27 @@
 // We start with sched_lock at 1 so that any kernel code we
 // call during initialization will not try to reschedule.
 
-volatile cyg_ucount32 Cyg_Scheduler_Base::sched_lock = 1;
+CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS;
+
+Cyg_Thread              *volatile Cyg_Scheduler_Base::current_thread[CYGNUM_KERNEL_CPU_MAX];
 
-Cyg_Thread            *Cyg_Scheduler_Base::current_thread = NULL;
+volatile cyg_bool       Cyg_Scheduler_Base::need_reschedule[CYGNUM_KERNEL_CPU_MAX];
+
+Cyg_Scheduler           Cyg_Scheduler::scheduler CYG_INIT_PRIORITY( SCHEDULER );
+
+volatile cyg_ucount32   Cyg_Scheduler_Base::thread_switches[CYGNUM_KERNEL_CPU_MAX];
 
-cyg_bool              Cyg_Scheduler_Base::need_reschedule = false;
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+CYG_BYTE cyg_sched_cpu_interrupt[CYGNUM_KERNEL_CPU_MAX][sizeof(Cyg_Interrupt)]
+                                 CYGBLD_ANNOTATE_VARIABLE_SCHED;
 
-Cyg_Scheduler         Cyg_Scheduler::scheduler CYG_INIT_PRIORITY( SCHEDULER );
+__externC cyg_ISR cyg_hal_cpu_message_isr;
+__externC cyg_DSR cyg_hal_cpu_message_dsr;
 
-cyg_ucount32          Cyg_Scheduler_Base::thread_switches = 0;
+inline void *operator new(size_t size, void *ptr) { return ptr; };
+
+#endif
 
 // -------------------------------------------------------------------------
 // Scheduler unlock function.
@@ -124,14 +136,14 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
     // it fail if the current thread that was about to sleep is awoken by
     // the DSR!  Going round the loop to run new DSRs does the same.
     CYG_ASSERT( (new_lock == 0) ||
-                (current_thread->state != Cyg_Thread::RUNNING ||
-                 need_reschedule) ,
+                (get_current_thread()->state != Cyg_Thread::RUNNING ||
+                 get_need_reschedule()) ,
                 "Unnecessary call to unlock_inner()" );
         
     do {
 
-        CYG_PRECONDITION( new_lock==0 ? sched_lock == 1 :
-                          ((sched_lock == new_lock) || (sched_lock == new_lock+1)),
+        CYG_PRECONDITION( new_lock==0 ? get_sched_lock() == 1 :
+                          ((get_sched_lock() == new_lock) || (get_sched_lock() == new_lock+1)),
                           "sched_lock not at expected value" );
         
 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
@@ -143,7 +155,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             Cyg_Interrupt::call_pending_DSRs();
 #endif
 
-        Cyg_Thread *current = current_thread;
+        Cyg_Thread *current = get_current_thread();
 
         CYG_ASSERTCLASS( current, "Bad current thread" );
 
@@ -154,7 +166,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             current->check_stack();
             current = current->get_list_next();
         }
-        current = current_thread;
+        current = get_current_thread();
 #endif
 
 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
@@ -164,7 +176,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
         // If the current thread is going to sleep, or someone
         // wants a reschedule, choose another thread to run
 
-        if( current->state != Cyg_Thread::RUNNING || need_reschedule ) {
+        if( current->state != Cyg_Thread::RUNNING || get_need_reschedule() ) {
 
             CYG_INSTRUMENT_SCHED(RESCHEDULE,0,0);
             
@@ -180,11 +192,12 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
                 CYG_INSTRUMENT_THREAD(SWITCH,current,next);
 
                 // Count this thread switch
-                thread_switches++;
-                
+                thread_switches[CYG_KERNEL_CPU_THIS()]++;
+
 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
                 next->check_stack(); // before running it
 #endif
+
                 // Switch contexts
                 HAL_THREAD_SWITCH_CONTEXT( &current->stack_ptr,
                                            &next->stack_ptr );
@@ -206,8 +219,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
                 CYG_CHECK_DATA_PTR( current, "Invalid current thread pointer");
                 CYG_ASSERTCLASS( current, "Bad current thread" );
 
-                current_thread = current;   // restore current thread pointer
-
+                current_thread[CYG_KERNEL_CPU_THIS()] = current;   // restore current thread pointer
             }
 
 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
@@ -216,7 +228,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             reset_timeslice_count();
 #endif
 
-            need_reschedule = false;        // finished rescheduling
+            clear_need_reschedule();    // finished rescheduling
         }
 
         if( new_lock == 0 )
@@ -242,7 +254,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             
             HAL_REORDER_BARRIER(); // Make sure everything above has happened
                                    // by this point
-            sched_lock = 0;        // Clear the lock
+            zero_sched_lock();     // Clear the lock
             HAL_REORDER_BARRIER();
                 
 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
@@ -254,14 +266,14 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             // not be run until the _next_ time we release the sched lock.
 
             if( Cyg_Interrupt::DSRs_pending() ) {
-                sched_lock = 1;     // reclaim the lock
+                inc_sched_lock();   // reclaim the lock
                 continue;           // go back to head of loop
             }
 
 #endif
             // Otherwise the lock is zero, we can return.
 
-            CYG_POSTCONDITION( sched_lock == 0, "sched_lock not zero" );
+//            CYG_POSTCONDITION( get_sched_lock() == 0, "sched_lock not zero" );
 
 #ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
             // If the test within the sched_lock indicating that the ASR
@@ -280,7 +292,7 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
             
             HAL_REORDER_BARRIER();
             
-            sched_lock = new_lock;
+            set_sched_lock(new_lock);
             
             HAL_REORDER_BARRIER();            
         }
@@ -297,19 +309,66 @@ void Cyg_Scheduler::unlock_inner( cyg_uc
 
 // -------------------------------------------------------------------------
 // Start the scheduler. This is called after the initial threads have been
-// created to start scheduling.
+// created to start scheduling. It gets any other CPUs running, and then
+// enters the scheduler.
 
 void Cyg_Scheduler::start()
 {
     CYG_REPORT_FUNCTION();
-        
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+    HAL_SMP_CPU_TYPE cpu;
+    
+    for( cpu = 0; cpu < CYG_KERNEL_CPU_COUNT(); cpu++ )
+    {
+        // Don't start this CPU, it is running already!
+        if( cpu == CYG_KERNEL_CPU_THIS() )
+            continue;
+
+        CYG_KERNEL_CPU_START( cpu );
+    }
+
+#endif    
+    
+    start_cpu();
+}
+
+// -------------------------------------------------------------------------
+// Start scheduling on this CPU. This is called on each CPU in the system
+// when it is started.
+
+void Cyg_Scheduler::start_cpu()
+{
+    CYG_REPORT_FUNCTION();
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+    // Set up the inter-CPU interrupt for this CPU
+
+    Cyg_Interrupt * intr = new( (void *)&cyg_sched_cpu_interrupt[HAL_SMP_CPU_THIS()] )
+        Cyg_Interrupt( CYGNUM_HAL_SMP_CPU_INTERRUPT_VECTOR( HAL_SMP_CPU_THIS() ),
+                       0,
+                       0,
+                       cyg_hal_cpu_message_isr,
+                       cyg_hal_cpu_message_dsr
+                     );
+
+    intr->set_cpu( intr->get_vector(), HAL_SMP_CPU_THIS() );
+    
+    intr->attach();
+
+    intr->unmask_interrupt( intr->get_vector() );
+    
+#endif    
+    
     // Get the first thread to run from scheduler
     register Cyg_Thread *next = scheduler.schedule();
 
     CYG_ASSERTCLASS( next, "Bad initial thread" );
 
-    need_reschedule = false;    // finished rescheduling
-    current_thread = next;      // restore current thread pointer
+    clear_need_reschedule();            // finished rescheduling
+    set_current_thread(next);           // restore current thread pointer
 
 #ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
     // Reference the real time clock. This ensures that at least one
@@ -318,14 +377,40 @@ void Cyg_Scheduler::start()
     CYG_REFERENCE_OBJECT( Cyg_Clock::real_time_clock );
 #endif
 
-    // Let the interrupts go
-    Cyg_Interrupt::enable_interrupts();
+    // Load the first thread. This will also enable interrupts since
+    // the initial state of all threads is to have interrupts enabled.
     
     HAL_THREAD_LOAD_CONTEXT( &next->stack_ptr );    
     
 }
 
 // -------------------------------------------------------------------------
+// SMP support functions
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+// This is called on each secondary CPU on its interrupt stack after
+// the initial CPU has initialized the world.
+
+externC void cyg_kernel_smp_startup()
+{
+    CYG_INSTRUMENT_SMP( CPU_START, CYG_KERNEL_CPU_THIS(), 0 );
+    Cyg_Scheduler::lock();
+    Cyg_Scheduler::start_cpu();
+}
+
+// This is called from the DSR of the inter-CPU interrupt to cause a
+// reschedule when the scheduler lock is zeroed.
+
+__externC void cyg_scheduler_set_need_reschedule()
+{
+    CYG_INSTRUMENT_SMP( RESCHED_RECV, 0, 0 );    
+    Cyg_Scheduler::need_reschedule[HAL_SMP_CPU_THIS()] = true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
 // Consistency checker
 
 #ifdef CYGDBG_USE_ASSERTS
@@ -342,7 +427,7 @@ cyg_bool Cyg_Scheduler::check_this( cyg_
     case cyg_system_test:
     case cyg_extreme:
     case cyg_thorough:
-        if( !current_thread->check_this(zeal) ) return false;
+        if( !get_current_thread()->check_this(zeal) ) return false;
     case cyg_quick:
     case cyg_trivial:
     case cyg_none:
@@ -382,9 +467,6 @@ Cyg_SchedThread::Cyg_SchedThread(Cyg_Thr
     CYG_REPORT_FUNCTION();
         
     queue = NULL;
-    
-    if( Cyg_Scheduler::current_thread == NULL )
-        Cyg_Scheduler::current_thread = thread;
 
 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL