驅動-定時-秒-字符設備

文章目錄

  • 目的
  • 相關資料參考
  • 實驗
    • 驅動程序-timer_dev.c
    • 編譯文件-Makefile
    • 測試程序-timer.c
      • 分析
  • 加載驅動-運行測試程序
  • 總結


目的

通過定時器timer_list、字符設備、規避競爭關系-原子操作,綜合運用 實現一個程序,加深之前知識的理解。

  • 實現字符設備驅動框架, 自動生成設備節點。
  • 根據上一小節學到的知識, 實現秒計時。
  • 通過原子變量來記錄遞增的秒數, 避免競爭的發生。
  • 通過用戶空間和內核空間的數據交換, 將記錄的秒數傳遞到應用空間, 并通過應用程
    序打印出來

相關資料參考

驅動-原子操作
驅動-Linux定時-timer_list

實驗

驅動程序-timer_dev.c


#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>struct device_test
{dev_t  dev_num;  //定義dev_t類型變量來表示設備號int major,minor; //定義int 類型的主設備號和次設備號struct cdev cdev_test;   //定義字符設備struct class *class;   //定義結構體變量class 類struct device *device;  // 設備int sec;               //秒};
atomic64_t v = ATOMIC_INIT(0);//定義原子類型變量v,并定義為0struct device_test dev1;  static void function_test(struct timer_list *t);//定義function_test定時功能函數
DEFINE_TIMER(timer_test,function_test);//定義一個定時器
static void function_test(struct timer_list *t)
{atomic64_inc(&v);//原子變量v自增dev1.sec = atomic_read(&v);//將讀取到的原子變量v,賦值給secprintk("the sec is %d\n",dev1.sec);mod_timer(&timer_test,jiffies_64 + msecs_to_jiffies(1000));//使用mod_timer函數將定時時間設置為一秒后
}/*打開設備函數*/
static int open_test(struct  inode  *inode,struct file *file){file->private_data=&dev1;//設置私有數據printk("\n this is open_test \n");add_timer(&timer_test);	//添加一個定時器return 0;};static ssize_t read_test(struct file *file, char __user *buf, size_t size, loff_t *off)
{if(copy_to_user(buf,&dev1.sec,sizeof(dev1.sec))){//使用copy_to_user函數將sec傳遞到應用層printk("copy_to_user error \n");return -1;}return 0;
}static int release_test(struct inode *inode,struct file *file)
{del_timer(&timer_test);//刪除一個定時器printk("\nthis is release_test \n");return 0;
}static struct file_operations fops_test = {.owner=THIS_MODULE,//將owner字段指向本模塊,可以避免在模塊的操作正在被使用時卸載該模塊.open = open_test,//將open字段指向chrdev_open(...)函數.read = read_test,//將open字段指向chrdev_read(...)函數.release = release_test,//將open字段指向chrdev_release(...)函數
};//定義file_operations結構體類型的變量cdev_test_opsstatic int __init timer_dev_init(void)//驅動入口函數
{if(alloc_chrdev_region(&dev1.dev_num,0,1,"chrdev_name") < 0){printk("alloc_chrdev_region is error\n");}   printk("alloc_chrdev_region is ok\n");dev1.major=MAJOR(dev1.dev_num);//通過MAJOR()函數進行主設備號獲取dev1.minor=MINOR(dev1.dev_num);//通過MINOR()函數進行次設備號獲取printk("major is %d\n",dev1.major);printk("minor is %d\n",dev1.minor);使用cdev_init()函數初始化cdev_test結構體,并鏈接到cdev_test_ops結構體cdev_init(&dev1.cdev_test,&fops_test);dev1.cdev_test.owner = THIS_MODULE;//將owner字段指向本模塊,可以避免在模塊的操作正在被使用時卸載該模塊 cdev_add(&dev1.cdev_test,dev1.dev_num,1);printk("cdev_add is ok\n");dev1.class  = class_create(THIS_MODULE,"test");//使用class_create進行類的創建,類名稱為class_testdevice_create(dev1.class,NULL,dev1.dev_num,NULL,"test");//使用device_create進行設備的創建,設備名稱為device_testreturn 0;
}
static void __exit timer_dev_exit(void)//驅動出口函數
{cdev_del(&dev1.cdev_test);//使用cdev_del()函數進行字符設備的刪除unregister_chrdev_region(dev1.dev_num,1);//釋放字符驅動設備號 device_destroy(dev1.class,dev1.dev_num);//刪除創建的設備class_destroy(dev1.class);//刪除創建的類printk("module exit \n");}
module_init(timer_dev_init);//注冊入口函數
module_exit(timer_dev_exit);//注冊出口函數
MODULE_LICENSE("GPL v2");//同意GPL開源協議
MODULE_AUTHOR("wang fang chen "); //作者信息

編譯文件-Makefile

#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
obj-m += timer_dev.o
KDIR :=/home/wfc123/Linux/rk356x_linux/kernel
PWD ?= $(shell pwd)
all:make -C $(KDIR) M=$(PWD) modulesclean:make -C $(KDIR) M=$(PWD) clean

測試程序-timer.c


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,char *argv[]){int fd;//定義int類型的文件描述符fdint count;//定義int類型記錄秒數的變量countfd = open("/dev/test",O_RDWR);//使用open()函數以可讀可寫的方式打開設備文件while(1){	read(fd,&count,sizeof(count));//使用read函數讀取內核傳遞來的秒數sleep(1);printf("num is %d\n",count);}return 0;
}

編譯測試程序變成可執行文件:

aarch64-linux-gnu-gcc -o timer timer.c

分析

通過函數 read(fd,&count,sizeof(count)) 調用, 為什么count 值會變化。 有的人會問,count 默認值是0 ,read 讀取。

ssize_t read(int fd, void *buf, size_t count);

函數read 參數解釋:

  • fd 參數代表文件描述符,是一個整數,用于標識要讀取的文件或設備。
  • buf 參數是一個指向緩沖區的指針,read 函數會將讀取的數據存儲在這個緩沖區中。
  • count 參數指定了最多要讀取的字節數。

這里好好思考一下如下,會不會有問題,需要理解清楚,思考清楚。

測試程序每隔1秒讀取count值 放到$count 緩沖區, 然后讀取;內核端每隔一秒增加sec 值,通過原子操作+1,然后內核層copy_to_user。 用戶層在緩沖區讀取的值就是內核層每隔一秒通過 buffer 傳遞過來的。

在這里插入圖片描述

加載驅動-運行測試程序

insmod timer_dev.ko./timer

實際返回值,如下:
在這里插入圖片描述

總結

這個程序實驗,用到了原子操作+定時器timer_list+字符設備操作。 簡要了解即可,加深前面知識印象。

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

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

相關文章

[Java實戰]Spring Boot整合Kafka:高吞吐量消息系統實戰(二十七)

[Java實戰]Spring Boot整合Kafka&#xff1a;高吞吐量消息系統實戰&#xff08;二十七&#xff09; 一、引言 Apache Kafka作為一款高吞吐量、低延遲的分布式消息隊列系統&#xff0c;廣泛應用于實時數據處理、日志收集和事件驅動架構。結合Spring Boot的自動化配置能力&…

Kotlin Multiplatform--04:經驗總結(持續更新)

Kotlin Multiplatform--04&#xff1a;經驗總結&#xff08;持續更新&#xff09; 引言 引言 本章用來記載筆者開發過程中的一些經驗總結 一、Ktor設置Header 在官方文檔中&#xff0c;想要設置Header的示例代碼如下&#xff1a; client.get("https://ktor.io&qu…

在 Ubuntu 系統中,將 JAR 包安裝為服務

在 Ubuntu 系統中&#xff0c;將 JAR 包安裝為服務可以通過 systemd 來實現。以下是詳細的操作步驟&#xff1a; 準備工作 確保 JAR 文件路徑和 Java 運行時環境已準備好。驗證 Java 是否可用&#xff1a; java -version創建 systemd 服務文件 systemd 的服務文件通常位于 …

電商項目-商品微服務-品牌管理微服務開發

一、功能分析 品牌管理微服務包括&#xff1a; &#xff08;1&#xff09;查詢全部列表數據 &#xff08;2&#xff09;根據ID查詢實體數據 &#xff08;3&#xff09;增加 &#xff08;4&#xff09;修改 &#xff08;5&#xff09;刪除 &#xff08;6&#xff09;分頁…

Spring Boot開發—— 整合Lucene構建輕量級毫秒級響應的全文檢索引擎

文章目錄 一、為什么選擇 Lucene?輕量級搜索的底層密碼二、核心原理:Lucene 的倒排索引2.1 倒排索引:速度之源2.2 段合并優化策略三、Spring Boot集成Lucene實戰3.1 依賴配置3.2 實體與索引設計3.3 核心索引服務(含異常處理)3.4 使用示例(測試類)四、高級優化技巧4.1 索…

SpringBootDay1|面試題

目錄 一、springboot框架 1、什么是springboot 2、Spring Boot的主要優點 3、springboot核心注解 4、定義banner&#xff08;springboot的logo&#xff09; 5、springboot配置文件 6、springboot 整合 jdbc 二、面試題 1&#xff09;springmvc的作用 ?編輯 2&#x…

jQuery Ajax中dataType 和 content-type 參數的作用詳解

jQuery Ajax中dataType與contentType參數解析 一、核心概念對比 參數作用對象數據類型默認值dataType響應數據預期接收的數據格式jQuery自動判斷&#xff08;根據響應頭MIME類型&#xff09;contentType請求數據發送數據的編碼格式application/x-www-form-urlencoded 二、da…

幾款常用的虛擬串口模擬器

幾款常用的虛擬串口模擬器&#xff08;Virtual Serial Port Emulator&#xff09;&#xff0c;適用于 Windows 系統&#xff0c;可用于開發和調試串口通信應用&#xff1a; 1. com0com (開源免費) 特點&#xff1a; 完全開源免費&#xff0c;無功能限制。 可創建多個虛擬串口…

LLM筆記(六)線性代數

公式速查表 1. 向量與矩陣&#xff1a;表示、轉換與知識存儲的基礎 向量表示 (Vectors): 語義的載體 在LLM中&#xff0c;向量 x ∈ R d \mathbf{x}\in\mathbb{R}^d x∈Rd 是信息的基本單元&#xff0c;承載著豐富的語義信息&#xff1a; 詞嵌入向量 (Word Embeddings)&am…

[特殊字符] Word2Vec:將詞映射到高維空間,它到底能解決什么問題?

一、在 Word2Vec 之前,我們怎么處理語言? 在 Word2Vec 出現之前,自然語言處理更多是“工程方法”,例如字符串匹配、關鍵詞提取、正則規則...。但這些表示通常缺乏語義,詞與詞之間看不出任何聯系以及非常淺顯。當然,技術沒有好壞,只有適合的場景。例如: 關鍵詞匹配非常…

棧和隊列的模擬實現

棧和隊列的模擬實現 容器適配器priority_queue(優先級隊列&#xff09;priority_queue的使用priority_queue的模擬實現&#xff1a; 仿函數什么叫仿函數&#xff1f;需要自己實現仿函數的情況&#xff1a; 棧的模擬實現隊列的模擬實現deque&#xff08;vector和list的縫合怪&am…

idea本地debug斷點小技巧

idea本地debug斷點小技巧 簡單的設置斷點條件 斷點后&#xff0c;右鍵這個斷點&#xff0c;可以在 condition 中填寫能得出布爾的表達式 a 1 你如果寫如下&#xff0c;表示先給他賦值&#xff0c;然后斷住 a 2; true 斷點后設置某個變量的值 在 debug 區域可以設置變量…

Oracle中如何解決FREE BUFFER WAITS

基于性能上的考慮&#xff0c;服務器進程在掃描LRU主列的同時&#xff0c;會將臟塊移至LRU-W列&#xff0c;如果發現沒有足夠可用&#xff08;可替換&#xff09;的BUFFER CACHE&#xff0c;進程并不會無止盡地掃描整條LRU主列&#xff0c;而是在掃描到某個閥值&#xff08;該閥…

Git命令使用全攻略:從創建分支到合并的完整流程

Git命令使用全攻略&#xff1a;從創建分支到合并的完整流程 引言一、初始化項目與基礎配置1.1 克隆遠程倉庫1.2 查看當前分支狀態 二、創建與管理分支2.1 從main分支創建新功能分支2.2 查看分支列表2.3 提交代碼到新分支2.4 推送分支到GitHub 三、版本發布與標簽管理3.1 創建輕…

MATLAB跳動的愛心

520&#xff0c;一個會動的心~~~ function particleHeart2 % author : slandarer% 所需匿名函數 col1Func(n) repmat([255,158,196]./255,[n,1])repmat([-39,-81,-56]./255,[n,1]).*rand([n,1]); col2Func(n) repmat([118,156,216]./255,[n,1])repmat([137,99,39].*.1./255,[n,…

Go的單測gomock及覆蓋率命令

安裝gomock&#xff1a; go get github.com/golang/mock/gomockgo get github.com/golang/mock/mockgen 使用 mockgen 生成 mock 代碼: 參考 mockgen -sourceservice/user.go -destinationservice /mocks/mock_user_service.go -packagemocks go test -coverprofilecoverage.ou…

vue添加loading后修復頁面渲染問題

問題&#xff1a;想要通過選擇流程&#xff08;1&#xff09;后加載出角色信息&#xff08;2&#xff09; 選擇后無法展示經過排查&#xff0c;再調用接口給角色數組賦值后&#xff0c;頁面在接口調用完之前就已經渲染完成。接口是采用的異步加載解決&#xff1a;loadingRoles…

Python入門手冊:Python簡介,什么是Python

在當今數字化時代&#xff0c;編程語言猶如一把把神奇的鑰匙&#xff0c;能夠開啟通往技術世界的大門。而Python&#xff0c;無疑是其中最閃耀的一顆明星。今天&#xff0c;就讓我們一起走進Python的世界&#xff0c;從它的起源、應用領域以及優缺點三個方面&#xff0c;來全面…

用PyTorch在超大規模下訓練深度學習模型:并行策略全解析

我猜咱們每個人肯定都累壞了&#xff0c;天天追著 LLM 研究社區跑&#xff0c;感覺每天都冒出個新的最牛模型&#xff0c;把之前的基準都給打破了呢。要是你好奇為啥創新速度能這么快&#xff0c;那主要就是研究人員能夠在超大規模下訓練和驗證模型啦&#xff0c;這全靠并行計算…

提示工程(Prompt Engineering)應用技巧

Prompt&#xff08;提示&#xff09;就是用戶與大模型交互輸入的代稱。即我們給大模型的輸入稱為 Prompt&#xff0c;而大模型返回的輸出一般稱為 Completion。 Prompt 需要清晰明確地表達需求&#xff0c;提供充足上下文&#xff0c;使語言模型能夠準確理解我們的意圖。更長、…