linux驅動——原子操作

linux驅動——原子操作

原子操作 API

Linux 內核定義了叫做 atomic_t 的結構體來完成整型數據的原操作,在使用是使用原子變量來代替整型變量。此結構體定義在 include/linux/types.h 文件中,定義如下:

typedef struct {int counter;
}atomic_t;

如果要使用原子操作 API 函數,需要首先定義一個 atomic_t 的變量,如下所示:

atomic_t value;  /* 定義一個原子變量 value */

也可以在定義原子變量的時候給原子變量賦初值,如下所示

atomic_t value = ATOMIC_INIT(0) /* 定義原子變量 value 并賦初值為 0*/

Linux 內核提供的原子變量操作的 API 如下:

函數描述
ATOMIC_INIT(int i)定義原子變量的時候初始化
int atomic_read(atomic_t *v)讀取原子變量 v 的值,并且返回
void atomic_set(atomic_t *v, int i)向 v 寫入 i 值
void atomic_add(int i, atomic_t *v)給 v 加上 i 值
void atomic_sub(int i, atomic_t *v)給 v 減去 i 值
void atomic_inc(atomic_t *v)自增
void atomic_dec(atomic_t *v)自減
int atomic_dec_return(atomic_t *v)自減,并返回 v 的值
int atomic_inc_return(atomic_t *v)自增,并返回 v 的值
int atomic_sub_and_test(int i, atomic_t *v)從 v 減 i,如果結果為 0 就返回真,否則返回假
int atomic_dec_and_test(atomic_t *v)從 v 減 1,如果結果為 0 就返回真,否則返回假
int atomic_inc_and_test(atomic_t *v)給 v 加 1,如果結果為 0 就返回真,否則返回假
int atomic_inc_and_test(atomic_t *v)給 v 加 1,如果結果為 0 就返回真,否則返回假
int atomic_add_negative(int i, atomic_t *v)給 v 加 i,如果結果為負就返回真,否則返回假

如果使用 64 位的 SOC 的話,就要用到 64 位的原子變量,Linux 內核也定義了 64 位原子結構體,如下所示:

#ifdef CONFIG_64BIT
typedef struct {s64 counter;
} atomic64_t;
#endif
typedef __s64 s64;
__extension__ typedef __signed__ long long __s64;

相應的也提供了 64 位原子變量的操作 API 函數,和上表用法一樣,只是將 atomic_ 前綴換為 atomic64_ 將 int 換為 long long。如果使用的是 64 位的 SOC,那么就要使用 64 位的原子操作函數。

原子變量使用示例如下:

atomic_t v = ATOMIC_INIT(0); /* 定義并初始化原子變零 v=0 */
atomic_set(&v, 10); /* 設置 v=10 */
atomic_read(&v); /* 讀取 v 的值,肯定是 10 */
atomic_inc(&v); /* v 的值加 1,v=11 */

原子位操作 API

位操作也是很常用的操作,Linux 內核也提供了一系列的原子位操作 API 函數,只不過原子位操作不像原子整形變量那樣有個 atomic_t 的數據結構,原子位操作是直接對內存進行操作,API 函數下所示:

函數描述
void set_bit(int nr, void *p)將 p 地址的第 nr 位置 1
void clear_bit(int nr,void *p)將 p 地址的第 nr 位清零
void change_bit(int nr, void *p)將 p 地址的第 nr 位進行翻轉
int test_bit(int nr, void *p)獲取 p 地址的第 nr 位的值
int test_and_set_bit(int nr, void *p)將 p 地址的第 nr 位置 1,并且返回 nr 位原來的值
int test_and_clear_bit(int nr, void *p)將 p 地址的第 nr 位清零,并且返回 nr 位原來的值
int test_and_change_bit(int nr, void *p)將 p 地址的第 nr 位翻轉,并且返回 nr 位原來的值

原子操作驅動

#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>#define CHRDEVBASE_NAME "chrdev_atom" /* 設備名 */
#define CHRDEVBASE_NUM 1              /* 設備數目 */static char write_buf[100];
static char read_buf[100];static char *string_test = "kernel data this tyustli test";typedef struct {dev_t dev_id;          /* 設備號 */struct cdev c_dev;     /* cdev */struct class *class;   /* 類 */struct device *device; /* 設備 */int major;             /* 主設備號 */int minor;             /* 次設備號 */atomic_t lock;         /* 原子鎖 */
} new_chrdev_t;new_chrdev_t new_chrdev;static int chrdevbase_open(struct inode *inode, struct file *file)
{/* 通過判斷原子變量的值來檢查當前驅動有沒有被別的應用使用 */if (!atomic_dec_and_test(&new_chrdev.lock)) {atomic_inc(&new_chrdev.lock); /* 小于 0 的話就加 1,使其原子變量等于 0 */return -EBUSY;                /* 驅動被使用,返回忙 */}printk("k: chrdevbase open\r\n");return 0;
}static ssize_t chrdevbase_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;printk("k: chrdevbase read\r\n");memcpy(read_buf, string_test, strlen(string_test));ret = copy_to_user(buf, read_buf, count);if (ret == 0) {printk("k: read data success\r\n");} else {printk("k: read data failed ret = %ld\r\n", ret);}return ret;
}static ssize_t chrdevbase_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;printk("k: chrdevbase write\r\n");ret = copy_from_user(write_buf, buf, count);if (ret == 0) {printk("k: write data success write data is: %s\r\n", write_buf);} else {printk("k: write data failed ret = %ld\r\n", ret);}return count;
}static int chrdevbase_release(struct inode *inode, struct file *file)
{/* 關閉驅動文件的時候釋放原子變量 */atomic_inc(&new_chrdev.lock);printk("k: chrdevbase release\r\n");return 0;
}static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};static int __init chrdevbase_init(void)
{int err = 0;atomic_set(&new_chrdev.lock, 1); /* 原子變量初始值為1 */err = alloc_chrdev_region(&new_chrdev.dev_id, 0, CHRDEVBASE_NUM,CHRDEVBASE_NAME);if (err < 0) {printk("k: alloc chrdev region failed err = %d\r\n", err);return -1;}/* get major and minor */new_chrdev.major = MAJOR(new_chrdev.dev_id);new_chrdev.minor = MINOR(new_chrdev.dev_id);printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev.major,new_chrdev.minor);new_chrdev.c_dev.owner = THIS_MODULE;cdev_init(&new_chrdev.c_dev, &chrdevbase_fops);err = cdev_add(&new_chrdev.c_dev, new_chrdev.dev_id, CHRDEVBASE_NUM);if (err < 0) {printk("k: cdev add failed err = %d\r\n", err);goto out;}new_chrdev.class = class_create(CHRDEVBASE_NAME);if (IS_ERR(new_chrdev.class)) {printk("k: class create failed\r\n");goto out_cdev;}new_chrdev.device = device_create(new_chrdev.class, NULL, new_chrdev.dev_id,NULL, CHRDEVBASE_NAME);if (IS_ERR(new_chrdev.device)) {printk("k: device create failed\r\n");goto out_class;}printk("k: base module init\r\n");return 0;out_class:class_destroy(new_chrdev.class);
out_cdev:cdev_del(&new_chrdev.c_dev);
out:unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);return err;
}static void __exit chrdevbase_exit(void)
{device_destroy(new_chrdev.class, new_chrdev.dev_id);class_destroy(new_chrdev.class);cdev_del(&new_chrdev.c_dev);unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);printk("k: base module exit!\r\n");
}module_init(chrdevbase_init);
module_exit(chrdevbase_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */

原子操作 APP

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"static char usrdata[] = { "user data!" };int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char run_cnt = 0;char readbuf[100], writebuf[100];if (argc != 3) {printf("u: error Usage!\r\n");return -1;}filename = argv[1];/* 打開驅動文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("u: can't open file %s\r\n", filename);return -1;}/* 從驅動文件讀取數據 */if (atoi(argv[2]) == 1) {retvalue = read(fd, readbuf, 50);if (retvalue < 0) {printf("u: read file %s failed!\r\n", filename);} else {/*  讀取成功,打印出讀取成功的數據 */printf("u: read data:%s\r\n", readbuf);}}/* 模擬占用驅動 25s,此時另一個線程去打開驅動 */while (1) {sleep(5);run_cnt++;if (run_cnt >= 5)break;}/* 向設備驅動寫數據 */if (atoi(argv[2]) == 2) {memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if (retvalue < 0) {printf("u: write file %s failed!\r\n", filename);}}/* 關閉設備 */retvalue = close(fd);if (retvalue < 0) {printf("u: can't close file %s\r\n", filename);return -1;}return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/161451.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/161451.shtml
英文地址,請注明出處:http://en.pswp.cn/news/161451.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

websocket與node.js實現

什么是 websocket&#xff1f; websoket 是一種網絡通信協議&#xff0c;基于 tcp 連接的全雙工通信協議&#xff08;客戶端和服務器可以同時收發信息&#xff09;&#xff0c;值得注意的是他不基于 http 協議&#xff0c;websocket 只有在建立連接的時候使用到 http 協議進行…

Kubernetes(k8s)之Pod詳解

文章目錄 Kubernetes之Pod詳解一、Pod介紹pod結構pod定義 二、Pod配置pod基本配置鏡像拉取策略啟動命令環境變量端口設置資源配額 三、Pod生命周期創建和終止初始化容器鉤子函數容器探測重啟策略 四、Pod調度定向調度NodeNameNodeSelector 親和性調度NodeAffinityPodAffinityPo…

風電場葉片運輸車模型-FBX格式-帶動畫-數字孿生場景搭建

FBX格式的風電場中葉片運輸車輛模型&#xff0c;按照真實尺寸建模&#xff0c;車輛多個部位帶動畫效果&#xff0c;適用于風電場三維數字化場景和風電場數字孿生使用&#xff0c;也可以用來作為各種三維平臺的測試模型。 模型效果圖 下載地址 葉片運輸車模型下載地址

php生成xml數據

在PHP中&#xff0c;你可以使用以下幾種方法生成XML數據&#xff1a; 使用DOM擴展&#xff1a; $xml new DOMDocument(1.0, UTF-8); $root $xml->createElement(root); $xml->appendChild($root); $child $xml->createElement(child); $root->appendChild($ch…

使用 Raspberry Pi、Golang 和 HERE XYZ 制作實時地圖

到目前為止&#xff0c;您可能已經看過我的一些與 Raspberry Pi 和位置數據相關的教程。我是這些小型物聯網 (IoT) 設備的忠實粉絲&#xff0c;并編寫了有關使用 Golang 進行 WLAN 定位 和 使用 Node.js 進行 GPS 定位的教程。 我想繼續沿著 Golang 路線&#xff0c;做一個關于…

目標檢測YOLO實戰應用案例100講-基于YOLO的小目標檢測改進算法

目錄 前言 國內外研究現狀 常規尺寸目標檢測算法 小目標的檢測算法

stm32定時器輸入捕獲模式

頻率測量 頻率測量有兩種方法 測頻法&#xff1a;在閘門時間T內&#xff0c;對上升沿或下降沿計次&#xff0c;得到N&#xff0c;則評率fxN/T測周法&#xff1a;兩個上升沿內&#xff0c;以標準頻率fc計次得到N&#xff0c;則頻率fx fc/N中界頻率&#xff1a;測頻法和測周法誤…

Spark的通用運行流程與Spark YARN Cluster 模式的運行流程

Spark的通用運行流程 集群啟動后Worker節點會向Master節點心跳匯報資源Client向Driver提交APP&#xff0c;根據不同的運行模式在不同的地方創建Driver。Driver以粗粒度的方式向Master注冊應用并申請資源&#xff08;在Application執行之前&#xff0c;將所有的資源申請完畢&…

助力企業前行——ScalaSpark最佳實踐課程

時間飛逝&#xff0c;轉眼間我們的Scala&Spark培訓課程已經圓滿結束&#xff01;在這段精彩的學習旅程中&#xff0c;你們展現了堅韌、決心和追求卓越的品質。 scala(Scalable Language)是一種多范式的編程語言&#xff0c;其設計的初衷是要集成面向對象編程和函數式編程的…

Cookie與Session知識

目錄 一.Cookie與Session的發展史 1.Cookie的發展史 2.Session的發展史 3.Cookie和Session的關系 4.總結 二.Cookie與Session詳解 1.Cookie 2.Session 3.token 4.總結 三.Django操作Cookie 1.設置Cookie 2.獲取Cookie 3.設置超時時間 4.注銷Cookie 5.登錄功能實…

【機器學習】On the Identifiability of Nonlinear ICA: Sparsity and Beyond

前言 本文是對On the Identifiability of Nonlinear ICA: Sparsity and Beyond (NIPS 2022)中兩個結構稀疏假設的總結。原文鏈接在Reference中。 什么是ICA(Independent component analysis)&#xff1f; 獨立成分分析簡單來說&#xff0c;就是給定很多的樣本X&#xff0c;通…

Springboot-熱部署-IDEA2023

方式一&#xff1a;jrebel 方式二&#xff1a; 1、導入依賴 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <…

C++ DAY08 異常

概念 異常事件&#xff08;如&#xff1a;除 0 溢出&#xff0c;數組下標越界&#xff0c;所要讀取的文件不存在 , 空指針&#xff0c;內存不足 等等&#xff09; 在 C 語言對錯誤的處理是兩種方法&#xff1a; 一是使用整型的返回值標識錯誤&#xff1b; 二是使用 errn…

自動解決IP沖突的問題 利用批處理更改末位IP循環+1直到網絡暢通為止 解放雙手 事半功倍

好久沒出來寫點什么了&#xff0c;難道今天有點時間&#xff0c;順便把這兩天碰到的問題出個解決方法吧。 這幾天去客戶那兒解決網絡問題&#xff0c;因為客戶的網絡是固定的靜態IP&#xff0c;因為沒做MAC綁定&#xff0c;IP固定在本地電腦上&#xff0c;只要上不了網&#xf…

PDF轉Word,1行Python代碼就夠了,免費用

大家好&#xff0c;這里是程序員晚楓。 今年十一假期沒出去旅游&#xff0c;在家里更新一套原創課程&#xff0c;&#x1f449;給小白的《50講Python自動化辦公》。 所有功能&#xff0c;都只需要1行代碼&#xff0c;非常適合非程序員入門Python使用。 目前全網播放量直逼100…

RK3588平臺開發系列講解(嵌入式AI篇)RKNPU詳解

文章目錄 一、CPU、GPU、FPGA和NPU介紹二、CPU、GPU、FPGA和NPU區別三、NPU 應用四、RKNPU沉淀、分享、成長,讓自己和他人都能有所收獲!?? ?? 本篇將給大家介紹什么是RKNPU。 一、CPU、GPU、FPGA和NPU介紹 二、CPU、GPU、FPGA和NPU區別 若考慮成本、功耗、計算能力以及體…

探秘開發app與小程序:一場技術與創新的博弈

app與小程序&#xff1a;一場技術與創新的博弈隨著科技的飛速發展&#xff0c;移動應用程序已經成為我們日常生活中不可或缺的一部分。在這個充滿競爭的時代&#xff0c;企業紛紛投身于開發各類移動應用&#xff0c;以期在市場中占據一席之地。然而&#xff0c;面對多樣化的應用…

PC訪問華為昇騰開發板的摸索過程

作者&#xff1a;朱金燦 來源&#xff1a;clever101的專欄 為什么大多數人學不會人工智能編程&#xff1f;>>> 最近要折騰華為昇騰開發板&#xff08;官方名稱叫&#xff1a;Atlas 200I DK&#xff09;。先是按照官方教程折騰&#xff1a;Atlas200DK環境部署。我發現…

Spark---轉換算子、行動算子、持久化算子

一、轉換算子和行動算子 1、Transformations轉換算子 1&#xff09;、概念 Transformations類算子是一類算子&#xff08;函數&#xff09;叫做轉換算子&#xff0c;如map、flatMap、reduceByKey等。Transformations算子是延遲執行&#xff0c;也叫懶加載執行。 2)、Transf…

Jina AI 的 8K 向量模型上線 AWS Marketplace,支持本地部署!

在當前多模態 AI 和大模型技術風頭正勁的背景下&#xff0c;Jina AI 始終領跑于創新前沿&#xff0c;技術領先。2023 年 10 月 30 日&#xff0c;Jina AI 隆重推出 jina-embeddings-v2&#xff0c;這是全球首款支持 8192 輸入長度的開源向量大模型&#xff0c;其性能媲美 OpenA…