📄 smp.txt
字号:
All existing synchronization mechanisms work as before in an SMPsystem. Additional synchronization mechanisms have been added toprovide explicit synchronization for SMP.A set of functions have been added to the Kernel and device driverAPIs to provide spinlocks:void cyg_spinlock_init( cyg_spinlock_t *lock, cyg_bool_t locked );void cyg_drv_spinlock_init( cyg_spinlock_t *lock, cyg_bool_t locked );void cyg_spinlock_destroy( cyg_spinlock_t *lock );void cyg_drv_spinlock_destroy( cyg_spinlock_t *lock );void cyg_spinlock_spin( cyg_spinlock_t *lock );void cyg_drv_spinlock_spin( cyg_spinlock_t *lock );void cyg_spinlock_clear( cyg_spinlock_t *lock );void cyg_drv_spinlock_clear( cyg_spinlock_t *lock );cyg_bool_t cyg_spinlock_try( cyg_spinlock_t *lock );cyg_bool_t cyg_drv_spinlock_try( cyg_spinlock_t *lock );cyg_bool_t cyg_spinlock_test( cyg_spinlock_t *lock );cyg_bool_t cyg_drv_spinlock_test( cyg_spinlock_t *lock );void cyg_spinlock_spin_intsave( cyg_spinlock_t *lock, cyg_addrword_t *istate );void cyg_drv_spinlock_spin_intsave( cyg_spinlock_t *lock, cyg_addrword_t *istate );void cyg_spinlock_clear_intsave( cyg_spinlock_t *lock, cyg_addrword_t istate );void cyg_drv_spinlock_clear_intsave( cyg_spinlock_t *lock, cyg_addrword_t istate );The *_init() functions initialize the lock, to either locked or clear,and the *_destroy() functions destroy the lock. Init() should be calledbefore the lock is used and destroy() should be called when it isfinished with.The *_spin() functions will cause the calling CPU to spin until it canclaim the lock and the *_clear() functions clear the lock so that thenext CPU can claim it. The *_try() functions attempts to claim the lockbut returns false if it cannot. The *_test() functions simply returnthe state of the lock.None of these functions will necessarily block interrupts while theyspin. If the spinlock is only to be used between threads on differentCPUs, or in circumstances where it is known that the relevantinterrupts are disabled, then these functions will suffice. However,if the spinlock is also to be used from an ISR, which may be called atany point, a straightforward spinlock may result in deadlock. Hencethe *_intsave() variants are supplied to disable interrupts while thelock is held.The *_spin_intsave() function disables interrupts, saving the currentstate in *istate, and then claims the lock. The *_clear_intsave()function clears the spinlock and restores the interrupt enable statefrom *istate.HAL Support-----------SMP support in any platform depends on the HAL supplying theappropriate operations. All HAL SMP support is defined in thehal_smp.h header (and if necessary var_smp.h and plf_smp.h).SMP support falls into a number of functional groups.CPU Control~~~~~~~~~~~This group consists of descriptive and control macros for managing theCPUs in an SMP system.HAL_SMP_CPU_TYPE A type that can contain a CPU id. A CPU id is usually a small integer that is used to index arrays of variables that are managed on an per-CPU basis.HAL_SMP_CPU_MAX The maximum number of CPUs that can be supported. This is used to provide the size of any arrays that have an element per CPU.HAL_SMP_CPU_COUNT() Returns the number of CPUs currently operational. This may differ from HAL_SMP_CPU_MAX depending on the runtime environment.HAL_SMP_CPU_THIS() Returns the CPU id of the current CPU.HAL_SMP_CPU_NONE A value that does not match any real CPU id. This is uses where a CPU type variable must be set to a nul value.HAL_SMP_CPU_START( cpu ) Starts the given CPU executing at a defined HAL entry point. After performing any HAL level initialization, the CPU calls up into the kernel at cyg_kernel_cpu_startup().HAL_SMP_CPU_RESCHEDULE_INTERRUPT( cpu, wait ) Sends the CPU a reschedule interrupt, and if _wait_ is non-zero, waits for an acknowledgment. The interrupted CPU should call cyg_scheduler_set_need_reschedule() in its DSR to cause the reschedule to occur.HAL_SMP_CPU_TIMESLICE_INTERRUPT( cpu, wait ) Sends the CPU a timeslice interrupt, and if _wait_ is non-zero, waits for an acknowledgment. The interrupted CPU should call cyg_scheduler_timeslice_cpu() to cause the timeslice event to be processed.Test-and-set Support~~~~~~~~~~~~~~~~~~~~Test-and-set is the foundation of the SMP synchronizationmechanisms.HAL_TAS_TYPE The type for all test-and-set variables. The test-and-set macros only support operations on a single bit (usually the least significant bit) of this location. This allows for maximum flexibility in the implementation.HAL_TAS_SET( tas, oldb ) Performs a test and set operation on the location _tas_. _oldb_ will contain *true* if the location was already set, and *false* if it was clear.HAL_TAS_CLEAR( tas, oldb ) Performs a test and clear operation on the location _tas_. _oldb_ will contain *true* if the location was already set, and *false* if it was clear.Spinlocks~~~~~~~~~Spinlocks provide inter-CPU locking. Normally they will be implementedon top of the test-and-set mechanism above, but may also beimplemented by other means if, for example, the hardware has moredirect support for spinlocks.HAL_SPINLOCK_TYPE The type for all spinlock variables.HAL_SPINLOCK_INIT_CLEAR A value that may be assigned to a spinlock variable to initialize it to clear.HAL_SPINLOCK_INIT_SET A value that may be assigned to a spinlock variable to initialize it to set.HAL_SPINLOCK_SPIN( lock ) The caller spins in a busy loop waiting for the lock to become clear. It then sets it and continues. This is all handled atomically, so that there are no race conditions between CPUs.HAL_SPINLOCK_CLEAR( lock ) The caller clears the lock. One of any waiting spinners will then be able to proceed.HAL_SPINLOCK_TRY( lock, val ) Attempts to set the lock. The value put in _val_ will be *true* if the lock was claimed successfully, and *false* if it was not.HAL_SPINLOCK_TEST( lock, val ) Tests the current value of the lock. The value put in _val_ will be *true* if the lock is claimed and *false* of it is clear.Scheduler Lock~~~~~~~~~~~~~~The scheduler lock is the main protection for all kernel datastructures. By default the kernel implements the scheduler lock itselfusing a spinlock. However, if spinlocks cannot be supported by thehardware, or there is a more efficient implementation available, theHAL may provide macros to implement the scheduler lock.HAL_SMP_SCHEDLOCK_DATA_TYPE A data type, possibly a structure, that contains any data items needed by the scheduler lock implementation. A variable of this type will be instantiated as a static member of the Cyg_Scheduler_SchedLock class and passed to all the following macros.HAL_SMP_SCHEDLOCK_INIT( lock, data ) Initialize the scheduler lock. The _lock_ argument is the scheduler lock counter and the _data_ argument is a variable of HAL_SMP_SCHEDLOCK_DATA_TYPE type.HAL_SMP_SCHEDLOCK_INC( lock, data ) Increment the scheduler lock. The first increment of the lock from zero to one for any CPU may cause it to wait until the lock is zeroed by another CPU. Subsequent increments should be less expensive since this CPU already holds the lock. HAL_SMP_SCHEDLOCK_ZERO( lock, data ) Zero the scheduler lock. This operation will also clear the lock so that other CPUs may claim it. HAL_SMP_SCHEDLOCK_SET( lock, data, new ) Set the lock to a different value, in _new_. This is only called when the lock is already known to be owned by the current CPU. It is never called to zero the lock, or to increment it from zero.Interrupt Routing~~~~~~~~~~~~~~~~~The routing of interrupts to different CPUs is supported by two newinterfaces in hal_intr.h.Once an interrupt has been routed to a new CPU, the existing vectormasking and configuration operations should take account of the CPUrouting. For example, if the operation is not invoked on thedestination CPU itself, then the HAL may need to arrange to transferthe operation to the destination CPU for correct application.HAL_INTERRUPT_SET_CPU( vector, cpu ) Route the interrupt for the given _vector_ to the given _cpu_. HAL_INTERRUPT_GET_CPU( vector, cpu ) Set _cpu_ to the id of the CPU to which this vector is routed.Annex 1 - Pentium SMP Support=============================ECos supports SMP working on Pentium class IA32 CPUs with integratedSMP support. It uses the per-CPU APIC's and the IOAPIC to provide CPUcontrol and identification, and to distribute interrupts. Only PCIinterrupts that map into the ISA interrupt space are currentlysupported. The code relies on the MP Configuration Table supplied bythe BIOS to discover the number of CPUs, IOAPIC location and interruptassignments - hardware based MP configuration discovery isnot currently supported. Inter-CPU interrupts are mapped into interrupt vectors from 64up. Each CPU has its own vector at 64+CPUID.Interrupt delivery is initially configured to deliver all interruptsto the initial CPU. HAL_INTERRUPT_SET_CPU() currently only supportsthe ability to deliver interrupts to specific CPUs, dynamic CPUselection is not currently supported.eCos has only been tested in a dual processor configuration. While thecode has been written to handle an arbitrary number of CPUs, this hasnot been tested.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -