歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> uclinux-2008R1-RC8(bf561)到VDSP5的移植(29):spinlock

uclinux-2008R1-RC8(bf561)到VDSP5的移植(29):spinlock

日期:2017/3/3 16:43:37   编辑:關於Linux

spinlock是用於線程間同步的自旋鎖,由於我們希望使用BF561的兩個核,因此它就顯得極為重要。

1 定義

在內核中聲明一個spinlock可以使用DEFINE_SPINLOCK這個宏定義,它的定義在include/linux/spinlock_types.h中:

#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x)

其中spinlock_t是在include/linux/spinlock_types.h中定義的一個結構體:

typedef struct {
 raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
 unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
 unsigned int magic, owner_cpu;
 void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
 struct lockdep_map dep_map;
#endif
} spinlock_t;

因為我們只定義了CONFIG_SMP,因此這個結構體實際就是:

typedef struct {
 raw_spinlock_t raw_lock;
} spinlock_t;

raw_spinlock_t的定義在include/asm/spinlock_types.h中:

typedef struct {
 volatile unsigned int lock;
} raw_spinlock_t;

在此之前,我們只是簡單地將其設置為volatile unsigned int的類型,而現在,我們則希望借助於VDSP的庫進行核間同步,因此將其定義改為:

typedef struct {
 testset_t lock;
} raw_spinlock_t;

因為testset_t自動就是volatile類型的,在此就不用聲明了。

2 VDSP對核間同步的支持

以下內容來自VDSP的幫助:

Synchronization Functions
VisualDSP++ 5.0 provides functionality for synchronization. There are two compiler intrinsics (built-in functions) and three locking routines.
The compiler intrinsics are:
#include <ccblkfn.h>
int testset(char *);
void untestset(char *);
The testset() intrinsic generates a native TESTSET instruction, which can perform atomic updates on a memory location. The intrinsic returns the result of the CC flag produced by the TESTSET instruction. Refer to the instruction set reference for details.
The untestset() intrinsic clears the memory location set by the
testset() intrinsic. This intrinsic is recommended in place of a normal memory write because the untestset() intrinsic acts as a stronger barrier to code movement during optimization.
The three locking routines are:
#include <ccblkfn.h>
void adi_acquire_lock(testset_t *);
int adi_try_lock(testset_t *);
void adi_release_lock(testset_t *);
The adi_acquire_lock() routine repeatedly attempts to claim the lock by issuing testset() until successful, whereupon it returns to the caller. In contrast, the adi_try_lock() routine makes a single attempt—if it successfully claims the lock, it returns nonzero, otherwise it returns zero.
The adi_release_lock() routine releases the lock obtained by either adi_acquire_lock() or adi_try_lock(). It assumes that the lock was already claimed and makes no attempt to verify that its caller is in fact the current owner of the lock. None of these intrinsics or functions disable interrupts—that is left to the caller’s discretion.

3 spin_lock

spin_lock的定義在include/linux/spinlock.h中:

#define spin_lock(lock)  _spin_lock(lock)

_spin_lock的定義在include/linux/spinlock_api_smp.h中:

void __lockfunc _spin_lock(spinlock_t *lock)  __acquires(lock);

而其實現則在kernel/spinlock.c中:

void __lockfunc _spin_lock(spinlock_t *lock)
{
 preempt_disable();
 spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
 _raw_spin_lock(lock);
}

_raw_spin_lock的實現則是不同的體系結構有不同的方法,但是其實現一般都放在asm/spinlock.h中,我們也這樣做:

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
 adi_acquire_lock(&lock->lock);
}

4 .spinlock.text

uclinux為spinlock相關的函數定義了一個段:

#define __lockfunc fastcall __attribute__((section(".spinlock.text")))

因此我們需要在LDF文件中加上它:

.text
{
INPUT_SECTION_ALIGN(4)
. = (. + 3) / 4 * 4;
 __text = .;
 _text = .;
 __stext = .;

INPUT_SECTIONS($OBJECTS_CORE_A(sdram_bank0) $LIBRARIES_CORE_A(sdram_bank0))
INPUT_SECTIONS($OBJECTS_CORE_A(VDK_ISR_code) $LIBRARIES_CORE_A(VDK_ISR_code))
INPUT_SECTIONS($OBJECTS_CORE_A(program) $LIBRARIES_CORE_A(program))
INPUT_SECTIONS($OBJECTS_CORE_A(noncache_code) $LIBRARIES_CORE_A(noncache_code))

INPUT_SECTIONS($LIBRARIES_CORE_A(.text.*))
INPUT_SECTIONS($LIBRARIES_CORE_A(.fixup))
INPUT_SECTIONS($LIBRARIES_CORE_A(.spinlock.text))

INPUT_SECTION_ALIGN(16)
. = (. + 15) / 16 * 16;
___start___ex_table = .;
INPUT_SECTIONS($LIBRARIES_CORE_A(__ex_table))
___stop___ex_table = .;

INPUT_SECTION_ALIGN(4)
. = (. + 3) / 4 * 4;
 __etext = .;
} > MEM_SDRAM

Copyright © Linux教程網 All Rights Reserved