linux内核的原子操作简述
前言
原子操作可以保证对一个整型数据的修改是排他性的。Linux内核提供了一系列函数来实现内核中的原子操作,这些函数又分为两类,分别针对位和整型变量进行原子操作。位和整型变量的原子操作都依赖于底层CPU的原子操作,因此所有这些函数都与CPU架构密切相关。对于ARM处理器而言,底层使用LDREX和STREX指令,比如atomic_inc()底层的实现会调用到atomic_add()。
头文件Types.h (include\linux)
#include <linux/types.h>
一 整形原子操作相关函数和宏
给原子变量v的值加1
static inline void atomic_inc(atomic_t *v)
{atomic_add_return(1, v);
}
给原子变量的值减1
static inline void atomic_dec(atomic_t *v)
{atomic_sub_return(1, v);
}
给原子变量v加i
static inline void atomic_add(int i, atomic_t *v)
{atomic_add_return(i, v);
}
给原子变量v减i
static inline void atomic_sub(int i, atomic_t *v)
{atomic_sub_return(i, v);
}
三个宏
#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
atomic_inc_and_test东西,就是给原子变量+1,然后,在判断它当前的值是否等于0,其他两个相同。
定义并初始化给原子变量的值:
atomic_t atomic_count;
atomic_set(cm_dev->atomic_count,0);
二 整形原子操作使用方法
atomic_t atomic_count;
atomic_set(&atomic_count,0);
atomic_dec(&atomic_count);//自减1
atomic_inc(&atomic_count);//自增1
atomic_add(5,&atomic_count);//给原子变量加5
atomic_sub(5,&atomic_count);//给原子变量减5if(atomic_dec_and_test(&atomic_count)){printk("原子变量变成0啦\n");
}
三 位原子操作
位原子操作函数主要是用于寄存器的设置。
读取nr位的值
static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
{return ((1UL << (nr % __BITS_PER_LONG)) &(((unsigned long *)addr)[nr / __BITS_PER_LONG])) != 0;
}
设置nr为1
/*** set_bit - Atomically set a bit in memory* @nr: the bit to set* @addr: the address to start counting from** This function is atomic and may not be reordered. See __set_bit()* if you do not require the atomic guarantees.** Note: there are no guarantees that this function will not be reordered* on non x86 architectures, so if you are writing portable code,* make sure not to rely on its reordering guarantees.** Note that @nr may be almost arbitrarily large; this function is not* restricted to acting on a single-word quantity.*/
static inline void set_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p |= mask;_atomic_spin_unlock_irqrestore(p, flags);
}
对nr为取反
/*** change_bit - Toggle a bit in memory* @nr: Bit to change* @addr: Address to start counting from** change_bit() is atomic and may not be reordered. It may be* reordered on other architectures than x86.* Note that @nr may be almost arbitrarily large; this function is not* restricted to acting on a single-word quantity.*/
static inline void change_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p ^= mask;_atomic_spin_unlock_irqrestore(p, flags);
}
设置nr为0
/*** clear_bit - Clears a bit in memory* @nr: Bit to clear* @addr: Address to start counting from** clear_bit() is atomic and may not be reordered. However, it does* not contain a memory barrier, so if it is used for locking purposes,* you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()* in order to ensure changes are visible on other processors.*/
static inline void clear_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p &= ~mask;_atomic_spin_unlock_irqrestore(p, flags);
}
设置n位为1,并返回原来的值
/*** test_and_set_bit - Set a bit and return its old value* @nr: Bit to set* @addr: Address to count from** This operation is atomic and cannot be reordered.* It may be reordered on other architectures than x86.* It also implies a memory barrier.*/
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old | mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}
设置nr位为0,并返回原来的值
/*** test_and_clear_bit - Clear a bit and return its old value* @nr: Bit to clear* @addr: Address to count from** This operation is atomic and cannot be reordered.* It can be reorderdered on other architectures other than x86.* It also implies a memory barrier.*/
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old & ~mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}
对nr位取反,并返回原来的值
/*** test_and_change_bit - Change a bit and return its old value* @nr: Bit to change* @addr: Address to count from** This operation is atomic and cannot be reordered.* It also implies a memory barrier.*/
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old ^ mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}
使用示例
static atomic_t xxx_available = ATOMIC_INIT(1); /* 定义原子变量*/static int xxx_open(struct inode *inode, struct file *filp)
{...if (!atomic_dec_and_test(&xxx_available)) {atomic_inc(&xxx_available);return - EBUSY; /* 已经打开*/}...return 0; /* 成功 */
}static int xxx_release(struct inode *inode, struct file *filp)
{atomic_inc(&xxx_available); /* 释放设备 */return 0;
}
结束
linux内核的原子操作简述相关推荐
- uboot和linux内核移植流程简述
一.移植uboot流程 1.从半导体芯片厂下载对应的demo,然后编译测试demo版的uboot 开发板基本都是参考半导体厂商的 dmeo 板,而半导体厂商会在他们自己的开发板上移植好 uboot.l ...
- linux内核经常用到的 一个概念“原子操作“
原子这个概念和我们高中时候学到的物理的概念应该是相同的 但是什么是原子操作: 简单理解就是不可中断的操作 但是可以看一下他的原定义: 经某一操作系统调用所要完成的各个动作作为不可中断的操作,[毕竟(物 ...
- Linux内核之内核同步(二)——原子操作
原子操作 原子操作可以保证指令以原子的方式被执行,执行过程不会被打断.Linux内核提供了一个专门的atomic_t类型(一个原子访问计数器),其定义如下: typedef struct{int co ...
- 大话Linux内核中锁机制之原子操作、自旋锁【转】
转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...
- linux 内核同步--理解原子操作、自旋锁、信号量(可睡眠)、读写锁、RCU锁、PER_CPU变量、内存屏障
内核同步 内核中可能造成并发的原因: 中断–中断几乎可以在任何时刻异步发生,也就可以随时打断当前正在执行的代码. 软中断和tasklet–内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在 ...
- 【Linux】linux内核原子操作的实现
所谓原子操作,就是"不可中断的一个或一系列操作". 硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作&qu ...
- linux内核原子操作的实现
所谓原子操作,就是"不可中断的一个或一系列操作". 硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作&qu ...
- 原子操作 - linux内核锁(一)
"原子"是不可分割的意思,原子操作是指一个实际运行的操作不可分割,这个运行必然会被执行并完成而不会被另外一个任务或者事件打断.也就说,它是最小的执行单位,不可能有比它更小的执行单位 ...
- linux内核原子操作使用简介
驱动开发住常见的一个问题:就是一个驱动可以被多个进程同时打开,使用,这样会导致驱动功能混乱. ./app & ./app & ./app 可以同时打开这个设备,可通过文件描述符调用 ...
最新文章
- 预训练是 AI 未来所需要的全部吗?
- SpringBoot中使用@Mapper注解需要哪个包
- c++ 类的继承与派生
- Codeforces626B - Cards【模拟】
- python教授_Python为何如此优秀?斯坦福教授告诉你!
- python魔法方法与函数_在Python中画图(基于Jupyter notebook的魔法函数)
- java之歌_程序员之歌
- 谁说Dota2赢了人类的AI太水?连比尔·盖茨都啧啧称赞了
- -bash: pip: command not found错误
- java使用org.w3c.dom解析XML文档,创建、增删查改,保存,读取,遍历元素等操作
- 计算机精品视频教程合集
- 推荐一款能够将爱奇艺qsv、腾讯qlv、优酷kux完美转换成mp4的三合一全能格式转换器
- VelocityTracker使用总结
- 【规范】万字集大成的SCHPCB设计规范和AD的使用
- 搭建ftp服务器根目录文件夹,ftp服务器根目录传文件夹
- 压六类双绞线网线水晶头,
- 微信 及支付宝 支付接口 功能
- SpringBoot企业微信点餐系统
- MobaXterm登录密码重置
- 软件测试需要掌握的技能