seqlock分析

当需要同步的数据比较简单,且是多读少写,且写优先的,情况下

你可以使用 seqlock

seqlock 的底层是用spin实现,所以自然继承了spin的特性
如: 禁止抢占,sleep 等

typedef struct {
 unsigned sequence;
 spinlock_t lock;
} seqlock_t;

序列号初始化为0,即偶数,代表没有上锁

#define seqlock_init(x)     \
 do {      \
  (x)->sequence = 0;   \
  spin_lock_init(&(x)->lock);  \
 } while (0)


写操作,比较简单,只是对序列号++而已,而这个正式精华

(想想为什么不是++  —— 而只是++)

static inline void write_seqlock(seqlock_t *sl)
{
	spin_lock(&sl->lock);
	++sl->sequence;
	smp_wmb();
}

static inline void write_sequnlock(seqlock_t *sl)
{
	smp_wmb();
	sl->sequence++;
	spin_unlock(&sl->lock);
}

 使用例子: 

 write_seqlock(&xtime_lock);
                // 做些写的操作
                // 。。。。。。。
  write_sequnlock(&xtime_lock);


关键是seqlock对数据的读实现及读取方式

static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
{
	unsigned ret;

repeat:
	ret = sl->sequence;
	smp_rmb();
        // 偶数代表锁释放(初始值为0)
        // sequence只要 ++ 就够了
	if (unlikely(ret & 1)) {
		cpu_relax();
		goto repeat;
	}
	return ret;
}

// 加入序列号有改变的话,说明在这段时间里面写操作有可以改变了数据
static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)
{
	smp_rmb();

	return (sl->sequence != start);
}

 

// 举个栗子
// 参考 /kernel/kernel/hrtimer.c
static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
{
	ktime_t xtim, tomono;
	struct timespec xts, tom;
	unsigned long seq;

        // 两次返回的值不一样则一致循环
        // 比较 sequence
        // 这样的好处是,对于写没有影响
	do {
		seq = read_seqbegin(&xtime_lock);
		xts = __current_kernel_time();
		tom = wall_to_monotonic;
	} while (read_seqretry(&xtime_lock, seq));
       ................
}


 

你可能感兴趣的:(linux,kernel,seqlock)