亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

spinlock和spin_lock_bh對中斷下半部(軟中斷)的作用

2024-09-06 10:11:57
41
0

在內核程序開發中,我們經常會使用spin_lock對數據修改進行保護,常規模式如下:

int g_data = 0;

functiona()

{

spin_lock(&g_lock);

//modify global shared data

g_data = 1;

spin_unlock(&g_lock);

}

看上去是沒問題了,但在某些情況下,出現了deadlock, 并且原因就是在同一個cpu核上執行functiona的spin_lock 2次導致死鎖.

原因是因為functiona會在線程中被執行,也會在軟中斷被執行. 當functiona先在線程中執行,并且處于spin_lock()和spin_unlock()之間.

此刻,同cpu核上軟中斷被執行,搶占了當前線程,并且該軟中斷也調用函數functiona, 然后執行spin_lock()函數,便出現死鎖了.

修改方法是把spin_lock()/spin_unlock()改為spin_lock_bh()/spin_unlock_bh(),因為spin_lock_bh()會關閉當前cpu核中斷后半部(也就是軟中斷softirq).

還有spin_lock_irqsave(),會關閉當前cpu核的中斷和軟中斷.

 

spinlock 是怎么實現的?

看一下源代碼:

typedef struct spinlock {
	union {
		struct raw_spinlock rlock;
 
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
		struct {
			u8 __padding[LOCK_PADSIZE];
			struct lockdep_map dep_map;
		};
#endif
	};
} spinlock_t;

typedef struct raw_spinlock {
	arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
	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
} raw_spinlock_t;

typedef struct {
	union {
		u32 slock;
		struct __raw_tickets {
#ifdef __ARMEB__
			u16 next;
			u16 owner;
#else
			u16 owner;
			u16 next;
#endif
		} tickets;
	};
} arch_spinlock_t;

如果忽略 CONFIG_DEBUG_LOCK_ALLOC 話,spinlock 主要包含一個arch_spinlock_t的結構,從名字可以看出,這個結構是跟體系結構有關的。

lock操作, 以spin_lock為例:

static inline void spin_lock(spinlock_t *lock)
{
    raw_spin_lock(&lock->rlock);
}

define raw_spin_lock(lock)    _raw_spin_lock(lock)

void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
    __raw_spin_lock(lock);
}

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
preempt_disable(); // preempt_disable()是用來關閉掉搶占的
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); // 內核用來調試用的
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
 
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
    __acquire(lock);
    arch_spin_lock(&lock->raw_lock);
}
以 x86 為例,arch_spin_trylock最終調用__ticket_spin_trylock函數。其源代碼如下:
// 定義在arch/x86/include/asm/spinlock_types.h
typedef struct arch_spinlock {
    union {
        __ticketpair_t head_tail;
        struct __raw_tickets {
            __ticket_t head, tail; // 注意,x86使用的是小端模式,存在高地址空間的是tail
        } tickets;
    };
} arch_spinlock_t;

// 定義在arch/x86/include/asm中
static __always_inline int __ticket_spin_trylock(arch_spinlock_t *lock)
{
    arch_spinlock_t old, new;
    // 獲取舊的ticket信息
    old.tickets = ACCESS_ONCE(lock->tickets);
    // head和tail不一致,說明鎖正被占用,加鎖不成功
    if (old.tickets.head != old.tickets.tail)
        return 0;

    new.head_tail = old.head_tail + (1 << TICKET_SHIFT); // 將tail + 1

    /* cmpxchg is a full barrier, so nothing can move before it */
    return cmpxchg(&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
}

從上述代碼中可知,__ticket_spin_trylock的核心功能,就是判斷自旋鎖是否被占用,如果沒被占用,嘗試原子性地更新lock中的head_tail的值,將 tail+1,返回是否加鎖成功。

 

而對于spin_lock_bh()和spin_lock_irqsave(),則分別多了一個阻止軟中斷和中斷.

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
unsigned long flags;
 
local_irq_save(flags); //保存并關閉當前cpu核心中斷
preempt_disable();
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* do_raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
do_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}
 
 
static inline void __raw_spin_lock_bh(raw_spinlock_t *lock)
{
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); //并關閉當前cpu核心軟中斷
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
0條評論
作者已關閉評論
gongw
9文章數
0粉絲數
gongw
9 文章 | 0 粉絲
原創

spinlock和spin_lock_bh對中斷下半部(軟中斷)的作用

2024-09-06 10:11:57
41
0

在內核程序開發中,我們經常會使用spin_lock對數據修改進行保護,常規模式如下:

int g_data = 0;

functiona()

{

spin_lock(&g_lock);

//modify global shared data

g_data = 1;

spin_unlock(&g_lock);

}

看上去是沒問題了,但在某些情況下,出現了deadlock, 并且原因就是在同一個cpu核上執行functiona的spin_lock 2次導致死鎖.

原因是因為functiona會在線程中被執行,也會在軟中斷被執行. 當functiona先在線程中執行,并且處于spin_lock()和spin_unlock()之間.

此刻,同cpu核上軟中斷被執行,搶占了當前線程,并且該軟中斷也調用函數functiona, 然后執行spin_lock()函數,便出現死鎖了.

修改方法是把spin_lock()/spin_unlock()改為spin_lock_bh()/spin_unlock_bh(),因為spin_lock_bh()會關閉當前cpu核中斷后半部(也就是軟中斷softirq).

還有spin_lock_irqsave(),會關閉當前cpu核的中斷和軟中斷.

 

spinlock 是怎么實現的?

看一下源代碼:

typedef struct spinlock {
	union {
		struct raw_spinlock rlock;
 
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
		struct {
			u8 __padding[LOCK_PADSIZE];
			struct lockdep_map dep_map;
		};
#endif
	};
} spinlock_t;

typedef struct raw_spinlock {
	arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
	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
} raw_spinlock_t;

typedef struct {
	union {
		u32 slock;
		struct __raw_tickets {
#ifdef __ARMEB__
			u16 next;
			u16 owner;
#else
			u16 owner;
			u16 next;
#endif
		} tickets;
	};
} arch_spinlock_t;

如果忽略 CONFIG_DEBUG_LOCK_ALLOC 話,spinlock 主要包含一個arch_spinlock_t的結構,從名字可以看出,這個結構是跟體系結構有關的。

lock操作, 以spin_lock為例:

static inline void spin_lock(spinlock_t *lock)
{
    raw_spin_lock(&lock->rlock);
}

define raw_spin_lock(lock)    _raw_spin_lock(lock)

void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
    __raw_spin_lock(lock);
}

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
preempt_disable(); // preempt_disable()是用來關閉掉搶占的
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); // 內核用來調試用的
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
 
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
    __acquire(lock);
    arch_spin_lock(&lock->raw_lock);
}
以 x86 為例,arch_spin_trylock最終調用__ticket_spin_trylock函數。其源代碼如下:
// 定義在arch/x86/include/asm/spinlock_types.h
typedef struct arch_spinlock {
    union {
        __ticketpair_t head_tail;
        struct __raw_tickets {
            __ticket_t head, tail; // 注意,x86使用的是小端模式,存在高地址空間的是tail
        } tickets;
    };
} arch_spinlock_t;

// 定義在arch/x86/include/asm中
static __always_inline int __ticket_spin_trylock(arch_spinlock_t *lock)
{
    arch_spinlock_t old, new;
    // 獲取舊的ticket信息
    old.tickets = ACCESS_ONCE(lock->tickets);
    // head和tail不一致,說明鎖正被占用,加鎖不成功
    if (old.tickets.head != old.tickets.tail)
        return 0;

    new.head_tail = old.head_tail + (1 << TICKET_SHIFT); // 將tail + 1

    /* cmpxchg is a full barrier, so nothing can move before it */
    return cmpxchg(&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
}

從上述代碼中可知,__ticket_spin_trylock的核心功能,就是判斷自旋鎖是否被占用,如果沒被占用,嘗試原子性地更新lock中的head_tail的值,將 tail+1,返回是否加鎖成功。

 

而對于spin_lock_bh()和spin_lock_irqsave(),則分別多了一個阻止軟中斷和中斷.

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
unsigned long flags;
 
local_irq_save(flags); //保存并關閉當前cpu核心中斷
preempt_disable();
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* do_raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
do_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}
 
 
static inline void __raw_spin_lock_bh(raw_spinlock_t *lock)
{
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); //并關閉當前cpu核心軟中斷
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
文章來自個人專欄
文章 | 訂閱
0條評論
作者已關閉評論
作者已關閉評論
0
0