diff packages/kernel/current/include/smp.hxx @ 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
children aa8364213009
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/include/smp.hxx
@@ -0,0 +1,453 @@
+#ifndef CYGONCE_KERNEL_SMP_HXX
+#define CYGONCE_KERNEL_SMP_HXX
+
+//==========================================================================
+//
+//      smp.hxx
+//
+//      SMP kernel support
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   nickg
+// Contributors:nickg
+// Date:        2001-02-10
+// Purpose:     Kernel SMP support
+// Description: If SMP support is configured into the kernel, then this file
+//              translates HAL defined macros into C and C++ classes and methods
+//              that can be called from the rest of the kernel. If SMP is not
+//              configured in, then the same classes and methods are defined here
+//              to operate correctly in a single CPU configuration.
+//              
+// Usage:       #include <cyg/kernel/smp.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h>          // assertion macros
+
+#include <cyg/hal/hal_intr.h>           // HAL_DISABLE_INTERRUPTS() etc.
+
+#include <cyg/kernel/instrmnt.h>
+
+//==========================================================================
+
+#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && (CYGPKG_HAL_SMP_SUPPORT)
+
+//==========================================================================
+// SMP support is included
+
+#define CYG_KERNEL_SMP_ENABLED
+
+// -------------------------------------------------------------------------
+// Get HAL support
+
+#include <cyg/hal/hal_smp.h>
+
+// -------------------------------------------------------------------------
+// Defined values
+// These all just map straight through to the HAL.
+
+#define CYGNUM_KERNEL_CPU_MAX           HAL_SMP_CPU_MAX
+
+#define CYG_KERNEL_CPU_COUNT()          HAL_SMP_CPU_COUNT()
+
+#define CYG_KERNEL_CPU_THIS()           HAL_SMP_CPU_THIS()
+
+#define CYG_KERNEL_CPU_NONE             HAL_SMP_CPU_NONE
+
+// -------------------------------------------------------------------------
+// CPU control
+
+#define CYG_KERNEL_CPU_START( __cpu ) HAL_SMP_CPU_START( __cpu )
+
+#define CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait ) \
+        HAL_SMP_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait )
+
+#define CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( __cpu, __wait ) \
+        HAL_SMP_CPU_TIMESLICE_INTERRUPT( __cpu, __wait )
+
+// -------------------------------------------------------------------------
+// Scheduler lock default implementation.
+
+// This implementation should serve for most targets. However, some
+// targets may have hardware or other features that make simple
+// spinlocks impossible, or allow us to implement the scheduler lock
+// in a more efficient manner. If that is the case then the HAL will
+// implement these macros itself.
+
+#ifndef HAL_SMP_SCHEDLOCK_DATA_TYPE
+
+#define HAL_SMP_SCHEDLOCK_DATA_TYPE struct hal_smp_schedlock_data_type
+
+struct hal_smp_schedlock_data_type {
+    HAL_SPINLOCK_TYPE           spinlock;
+    volatile HAL_SMP_CPU_TYPE   holder;
+};
+
+#define HAL_SMP_SCHEDLOCK_INIT( __lock, __data )        \
+CYG_MACRO_START                                         \
+{                                                       \
+    __lock = 1;                                         \
+    HAL_SPINLOCK_CLEAR(__data.spinlock);                \
+    HAL_SPINLOCK_SPIN(__data.spinlock);                 \
+    __data.holder = HAL_SMP_CPU_THIS();                 \
+}                                                       \
+CYG_MACRO_END
+
+
+#define HAL_SMP_SCHEDLOCK_INC( __lock, __data )                 \
+CYG_MACRO_START                                                 \
+{                                                               \
+    CYG_INTERRUPT_STATE __state;                                \
+    HAL_DISABLE_INTERRUPTS(__state);                            \
+    if( __data.holder == HAL_SMP_CPU_THIS() )                   \
+        __lock++;                                               \
+    else                                                        \
+    {                                                           \
+        CYG_INSTRUMENT_SMP(LOCK_WAIT,CYG_KERNEL_CPU_THIS(),0);  \
+        HAL_SPINLOCK_SPIN(__data.spinlock);                     \
+        __data.holder = HAL_SMP_CPU_THIS();                     \
+        __lock++;                                               \
+        CYG_INSTRUMENT_SMP(LOCK_GOT,CYG_KERNEL_CPU_THIS(),0);   \
+    }                                                           \
+    HAL_RESTORE_INTERRUPTS(__state);                            \
+}                                                               \
+CYG_MACRO_END
+
+#define HAL_SMP_SCHEDLOCK_ZERO( __lock, __data )                                                 \
+CYG_MACRO_START                                                                                  \
+{                                                                                                \
+    CYG_INTERRUPT_STATE __state;                                                                 \
+    HAL_DISABLE_INTERRUPTS(__state);                                                             \
+    CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Zeroing schedlock not owned by me!");      \
+    __lock = 0;                                                                                  \
+    __data.holder = HAL_SMP_CPU_NONE;                                                            \
+    HAL_SPINLOCK_CLEAR(__data.spinlock);                                                         \
+    HAL_RESTORE_INTERRUPTS(__state);                                                             \
+}                                                                                                \
+CYG_MACRO_END
+
+#define HAL_SMP_SCHEDLOCK_SET( __lock, __data, __new )                                          \
+CYG_MACRO_START                                                                                 \
+{                                                                                               \
+    CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Setting schedlock not owned by me!");     \
+    __lock = __new;                                                                             \
+}                                                                                               \
+CYG_MACRO_END
+
+#endif
+
+// -------------------------------------------------------------------------
+// SpinLock class
+// This class supplies a C++ wrapper for the HAL spinlock API.
+
+#ifdef __cplusplus
+
+#ifdef HAL_SPINLOCK_SPIN
+
+class Cyg_SpinLock
+{
+    HAL_SPINLOCK_TYPE   lock;
+
+public:
+
+    // Constructor, initialize the lock to clear
+    Cyg_SpinLock() { lock = HAL_SPINLOCK_INIT_CLEAR; };
+
+    ~Cyg_SpinLock()
+    {
+        CYG_ASSERT( !test(), "spinlock still claimed");
+    };
+    
+    // Spin on the lock.
+    void spin()
+    {
+        HAL_SPINLOCK_SPIN(lock);
+    };
+
+    // Clear the lock.
+    void clear()
+    {
+        HAL_SPINLOCK_CLEAR(lock);
+    };
+
+    // Try to claim the lock. Return true if successful, false if not.
+    cyg_bool trylock()
+    {
+        cyg_bool testval;
+        HAL_SPINLOCK_TRY(lock,testval);
+        return testval;
+    };
+
+    // Test the current value of the lock
+    cyg_bool test()
+    {
+        cyg_bool testval;
+        HAL_SPINLOCK_TEST(lock, testval);
+        return testval;
+    };
+
+
+    // The following two member functions are only necessary if the
+    // spinlock is to be used in an ISR. 
+    
+    // Claim the spinlock, but also mask this CPU's interrupts while
+    // we have it.
+    void spin_intsave(CYG_INTERRUPT_STATE *state)
+    {
+        HAL_DISABLE_INTERRUPTS(*state);
+        spin();
+    };
+
+    // Clear the lock, and restore the interrupt state saved in
+    // spin_intsave().
+    void clear_intsave(CYG_INTERRUPT_STATE state)
+    {
+        clear();
+        HAL_RESTORE_INTERRUPTS(state);
+    };
+};
+
+#endif
+
+// -------------------------------------------------------------------------
+// Scheduler lock class
+// This uses the scheduler lock API defined by the HAL, or the defaults
+// defined above.
+
+class Cyg_Scheduler_SchedLock
+{
+    static volatile cyg_ucount32 sched_lock         // lock counter
+                    CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
+                    CYGBLD_ANNOTATE_VARIABLE_SCHED
+                    ;
+    
+    static HAL_SMP_SCHEDLOCK_DATA_TYPE lock_data
+                                       CYGBLD_ANNOTATE_VARIABLE_SCHED;
+    
+protected:
+
+    Cyg_Scheduler_SchedLock()
+    {
+        HAL_SMP_SCHEDLOCK_INIT( sched_lock, lock_data );
+    };
+    
+    // Increment the scheduler lock. If this takes the lock from zero
+    // to one then this code must also do whatever is necessary to
+    // serialize CPUs through the scheduler.
+    static void inc_sched_lock()
+    {
+        CYG_INSTRUMENT_SMP(LOCK_INC,CYG_KERNEL_CPU_THIS(),0);
+        HAL_SMP_SCHEDLOCK_INC( sched_lock, lock_data );
+    };
+
+    // Zero the scheduler lock. This will release the CPU serializing
+    // lock and allow another CPU in.
+    static void zero_sched_lock()
+    {
+        CYG_INSTRUMENT_SMP(LOCK_ZERO,CYG_KERNEL_CPU_THIS(),0);
+        CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
+        HAL_SMP_SCHEDLOCK_ZERO( sched_lock, lock_data );
+    };
+    
+    // Set the scheduler lock to a non-zero value. Both the scheduler
+    // lock and the new value must be non-zero.
+    static void set_sched_lock(cyg_uint32 new_lock)
+    {
+        CYG_INSTRUMENT_SMP(LOCK_SET,CYG_KERNEL_CPU_THIS(),new_lock);        
+        CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
+        CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
+        HAL_SMP_SCHEDLOCK_SET( sched_lock, lock_data, new_lock );        
+    };
+
+    static cyg_ucount32 get_sched_lock()
+    {
+        return sched_lock;
+    };
+};
+
+#define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS                    \
+volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1;  \
+HAL_SMP_SCHEDLOCK_DATA_TYPE Cyg_Scheduler_SchedLock::lock_data;
+
+#endif // __cplusplus
+
+// -------------------------------------------------------------------------
+
+#else // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
+
+//==========================================================================
+// SMP support is NOT included.
+
+#undef CYG_KERNEL_SMP_ENABLED
+
+// -------------------------------------------------------------------------
+// Defined values
+// Supply a set of values that describe a single CPU system.
+
+#ifndef HAL_SMP_CPU_TYPE
+#define HAL_SMP_CPU_TYPE                cyg_uint32
+#endif
+
+#define CYGNUM_KERNEL_CPU_MAX           1
+
+#define CYG_KERNEL_CPU_COUNT()          1
+
+#define CYG_KERNEL_CPU_THIS()           0
+
+#define CYG_KERNEL_CPU_NONE             -1
+
+#define CYG_KERNEL_CPU_LOWPRI()         CYG_KERNEL_CPU_THIS()
+
+// -------------------------------------------------------------------------
+// SpinLock class
+// This single CPU version simply goes through the motions of setting
+// and clearing the lock variable for debugging purposes. 
+
+#ifdef __cplusplus
+
+class Cyg_SpinLock
+{
+    cyg_atomic          lock;
+
+public:
+
+    // Constructor, initialize the lock to clear
+    Cyg_SpinLock() { lock = 0; };
+
+    ~Cyg_SpinLock()
+    {
+        CYG_ASSERT( lock == 0, "spinlock still claimed");
+    };
+    
+    // Spin on the lock. In this case we just set it to 1 and proceed.
+    void spin()
+    {
+        CYG_ASSERT( lock == 0, "spinlock already claimed!");
+        lock = 1;
+    };
+
+    // Clear the lock. Again, just set the value.
+    void clear()
+    {
+        CYG_ASSERT( lock != 0, "spinlock already cleared!");
+        lock = 0;
+    };
+
+    // Try to claim the lock. Return true if successful, false if not.
+    cyg_bool trylock()
+    {
+        if( lock ) return false;
+        else { lock = 1; return true; }
+    };
+
+    // Test the current value of the lock
+    cyg_bool test() { return lock; };
+
+
+    // The following two member functions are only necessary if the
+    // spinlock is to be used in an ISR. 
+    
+    // Claim the spinlock, but also mask this CPU's interrupts while
+    // we have it.
+    void spin_intsave(CYG_INTERRUPT_STATE *state)
+    {
+        HAL_DISABLE_INTERRUPTS(*state);
+        spin();
+    };
+
+    // Clear the lock, and restore the interrupt state saved in
+    // spin_intsave().
+    void clear_intsave(CYG_INTERRUPT_STATE state)
+    {
+        clear();
+        HAL_RESTORE_INTERRUPTS(state);
+    };
+
+};
+
+// -------------------------------------------------------------------------
+// Scheduler lock class
+
+class Cyg_Scheduler_SchedLock
+{
+    static volatile cyg_ucount32 sched_lock         // lock counter
+                    CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
+                    CYGBLD_ANNOTATE_VARIABLE_SCHED
+                    ;
+    
+    // For non-SMP versions, the code here does the basic and obvious things.
+protected:
+
+    Cyg_Scheduler_SchedLock()
+    {
+        sched_lock = 1;
+    };
+    
+    // Increment the scheduler lock, possibly taking it from zero to
+    // one.
+    static void inc_sched_lock()
+    {
+        sched_lock++;
+    };
+
+    static void zero_sched_lock()
+    {
+        CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
+        sched_lock = 0;
+    };
+    
+    // Set the scheduler lock to a non-zero value. Both the scheduler
+    // lock and the new value must be non-zero.
+    static void set_sched_lock(cyg_uint32 new_lock)
+    {
+        CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
+        CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
+        sched_lock = new_lock;
+    };
+
+    static cyg_ucount32 get_sched_lock()
+    {
+        return sched_lock;
+    };
+};
+
+#define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS                    \
+volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1;
+
+#endif // __cplusplus
+
+#endif // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_SMP_HXX
+
+// EOF smp.hxx