chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)基礎(chǔ)總結(jié)(下篇)

Q4MP_gh_c472c21 ? 來(lái)源:未知 ? 作者:李建兵 ? 2018-03-15 09:17 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

14, 字符設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)基礎(chǔ)

主設(shè)備號(hào)和次設(shè)備號(hào)(二者一起為設(shè)備號(hào)):一個(gè)字符設(shè)備或塊設(shè)備都有一個(gè)主設(shè)備號(hào)和一個(gè)次設(shè)備號(hào)。主設(shè)備號(hào)用來(lái)標(biāo)識(shí)與設(shè)備文件相連的驅(qū)動(dòng)程序,用來(lái)反映設(shè)備類(lèi)型。次設(shè)備號(hào)被驅(qū)動(dòng)程序用來(lái)辨別操作的是哪個(gè)設(shè)備,用來(lái)區(qū)分同類(lèi)型的設(shè)備。linux內(nèi)核中,設(shè)備號(hào)用dev_t來(lái)描述,2.6.28中定義如下:

typedefu_long dev_t;

在32位機(jī)中是4個(gè)字節(jié),高12位表示主設(shè)備號(hào),低12位表示次設(shè)備號(hào)。

可以使用下列宏從dev_t中獲得主次設(shè)備號(hào):也可以使用下列宏通過(guò)主次設(shè)備號(hào)生成dev_t:

MAJOR(dev_tdev);MKDEV(intmajor,intminor);MINOR(dev_tdev);

分配設(shè)備號(hào)(兩種方法):(1)靜態(tài)申請(qǐng):

int register_chrdev_region(dev_t from,unsigned count,const char *name);

(2)動(dòng)態(tài)分配:

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name);

注銷(xiāo)設(shè)備號(hào):

void unregister_chrdev_region(dev_t from,unsigned count);

創(chuàng)建設(shè)備文件:利用cat/proc/devices查看申請(qǐng)到的設(shè)備名,設(shè)備號(hào)。(1)使用mknod手工創(chuàng)建:mknod filename type major minor(2)自動(dòng)創(chuàng)建;利用udev(mdev)來(lái)實(shí)現(xiàn)設(shè)備文件的自動(dòng)創(chuàng)建,首先應(yīng)保證支持udev(mdev),由busybox配置。在驅(qū)動(dòng)初始化代碼里調(diào)用class_create為該設(shè)備創(chuàng)建一個(gè)class,再為每個(gè)設(shè)備調(diào)用device_create創(chuàng)建對(duì)應(yīng)的設(shè)備。

15, 字符設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)

設(shè)備注冊(cè):字符設(shè)備的注冊(cè)分為三個(gè)步驟:(1)分配

cdev:struct cdev *cdev_alloc(void);

(2)初始化

cdev:void cdev_init(struct cdev *cdev,const struct file_operations *fops);

(3)添加

cdev:int cdev_add(struct cdev *p,dev_t dev,unsigned count)

設(shè)備操作的實(shí)現(xiàn):file_operations函數(shù)集的實(shí)現(xiàn)。

struct file_operations xxx_ops={.owner=THIS_MODULE,.llseek=xxx_llseek,.read=xxx_read,.write=xxx_write,.ioctl=xxx_ioctl,.open=xxx_open,.release=xxx_release,

};

特別注意:驅(qū)動(dòng)程序應(yīng)用程序的數(shù)據(jù)交換:驅(qū)動(dòng)程序和應(yīng)用程序的數(shù)據(jù)交換是非常重要的。file_operations中的read()和write()函數(shù),就是用來(lái)在驅(qū)動(dòng)程序和應(yīng)用程序間交換數(shù)據(jù)的。通過(guò)數(shù)據(jù)交換,驅(qū)動(dòng)程序和應(yīng)用程序可以彼此了解對(duì)方的情況。但是驅(qū)動(dòng)程序和應(yīng)用程序?qū)儆诓煌牡刂房臻g。驅(qū)動(dòng)程序不能直接訪(fǎng)問(wèn)應(yīng)用程序的地址空間;同樣應(yīng)用程序也不能直接訪(fǎng)問(wèn)驅(qū)動(dòng)程序的地址空間,否則會(huì)破壞彼此空間中的數(shù)據(jù),從而造成系統(tǒng)崩潰,或者數(shù)據(jù)損壞。安全的方法是使用內(nèi)核提供的專(zhuān)用函數(shù),完成數(shù)據(jù)在應(yīng)用程序空間和驅(qū)動(dòng)程序空間的交換。這些函數(shù)對(duì)用戶(hù)程序傳過(guò)來(lái)的指針進(jìn)行了嚴(yán)格的檢查和必要的轉(zhuǎn)換,從而保證用戶(hù)程序與驅(qū)動(dòng)程序交換數(shù)據(jù)的安全性。這些函數(shù)有:

unsignedlongcopy_to_user(void__user *to,constvoid*from,unsignedlongn);unsignedlongcopy_from_user(void*to,constvoid __user *from,unsignedlongn);

put_user(local,user);

get_user(local,user);

設(shè)備注銷(xiāo):

void cdev_del(struct cdev *p);

16,ioctl函數(shù)說(shuō)明

ioctl是設(shè)備驅(qū)動(dòng)程序中對(duì)設(shè)備的I/O通道進(jìn)行管理的函數(shù)。所謂對(duì)I/O通道進(jìn)行管理,就是對(duì)設(shè)備的一些特性進(jìn)行控制,例如串口的傳輸波特率、馬達(dá)的轉(zhuǎn)速等等。它的調(diào)用個(gè)數(shù)如下:

int ioctl(int fd,ind cmd,…);

其中fd就是用戶(hù)程序打開(kāi)設(shè)備時(shí)使用open函數(shù)返回的文件標(biāo)示符,cmd就是用戶(hù)程序?qū)υO(shè)備的控制命令,后面的省略號(hào)是一些補(bǔ)充參數(shù),有或沒(méi)有是和cmd的意義相關(guān)的。

ioctl函數(shù)是文件結(jié)構(gòu)中的一個(gè)屬性分量,就是說(shuō)如果你的驅(qū)動(dòng)程序提供了對(duì)ioctl的支持,用戶(hù)就可以在用戶(hù)程序中使用ioctl函數(shù)控制設(shè)備的I/O通道。

命令的組織是有一些講究的,因?yàn)槲覀円欢ㄒ龅矫詈驮O(shè)備是一一對(duì)應(yīng)的,這樣才不會(huì)將正確的命令發(fā)給錯(cuò)誤的設(shè)備,或者是把錯(cuò)誤的命令發(fā)給正確的設(shè)備,或者是把錯(cuò)誤的命令發(fā)給錯(cuò)誤的設(shè)備。

所以在Linux核心中是這樣定義一個(gè)命令碼的:

這樣一來(lái),一個(gè)命令就變成了一個(gè)整數(shù)形式的命令碼。但是命令碼非常的不直觀,所以L(fǎng)inuxKernel中提供了一些宏,這些宏可根據(jù)便于理解的字符串生成命令碼,或者是從命令碼得到一些用戶(hù)可以理解的字符串以標(biāo)明這個(gè)命令對(duì)應(yīng)的設(shè)備類(lèi)型、設(shè)備序列號(hào)、數(shù)據(jù)傳送方向和數(shù)據(jù)傳輸尺寸。點(diǎn)擊(此處)折疊或打開(kāi)

/*used tocreate numbers*/

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)

#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

#defin e_IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))

#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))

#define _IOWR_BAD(type,nr,size)_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

#define _IOC(dir,type,nr,size)\

(((dir)<<_IOC_DIRSHIFT)|\

((type)<<_IOC_TYPESHIFT)|\

((nr)<<_IOC_NRSHIFT)|\

((size)<<_IOC_SIZESHIFT))

17,文件私有數(shù)據(jù)

大多數(shù)linux的驅(qū)動(dòng)工程師都將文件私有數(shù)據(jù)private_data指向設(shè)備結(jié)構(gòu)體,read等個(gè)函數(shù)通過(guò)調(diào)用private_data來(lái)訪(fǎng)問(wèn)設(shè)備結(jié)構(gòu)體。這樣做的目的是為了區(qū)分子設(shè)備,如果一個(gè)驅(qū)動(dòng)有兩個(gè)子設(shè)備(次設(shè)備號(hào)分別為0和1),那么使用private_data就很方便。

這里有一個(gè)函數(shù)要提出來(lái):

container_of(ptr,type,member)//通過(guò)結(jié)構(gòu)體成員的指針找到對(duì)應(yīng)結(jié)構(gòu)體的的指針

其定義如下:

/**

*container_of-castamemberofastructureouttothecontainingstructure

*@ptr: thepointertothemember.

*@type: thetypeofthecontainerstructthisisembeddedin.

*@member: thenameofthememberwithinthestruct.

*

*/

#define container_of(ptr,type,member)({ \

const typeof(((type*)0)->member)*__mptr=(ptr); \

(type*)((char*)__mptr-offsetof(type,member));})

18,字符設(shè)備驅(qū)動(dòng)的結(jié)構(gòu)

可以概括如下圖:字符設(shè)備是3大類(lèi)設(shè)備(字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備)中較簡(jiǎn)單的一類(lèi)設(shè)備,其驅(qū)動(dòng)程序中完成的主要工作是初始化、添加和刪除cdev結(jié)構(gòu)體,申請(qǐng)和釋放設(shè)備號(hào),以及填充file_operation結(jié)構(gòu)體中操作函數(shù),并實(shí)現(xiàn)file_operations結(jié)構(gòu)體中的read()、write()、ioctl()等重要函數(shù)。如圖所示為cdev結(jié)構(gòu)體、file_operations和用戶(hù)空間調(diào)用驅(qū)動(dòng)的關(guān)系。

19, 自旋鎖與信號(hào)

為了避免并發(fā),防止競(jìng)爭(zhēng)。內(nèi)核提供了一組同步方法來(lái)提供對(duì)共享數(shù)據(jù)的保護(hù)。我們的重點(diǎn)不是介紹這些方法的詳細(xì)用法,而是強(qiáng)調(diào)為什么使用這些方法和它們之間的差別。

Linux使用的同步機(jī)制可以說(shuō)從2.0到2.6以來(lái)不斷發(fā)展完善。從最初的原子操作,到后來(lái)的信號(hào)量,從大內(nèi)核鎖到今天的自旋鎖。這些同步機(jī)制的發(fā)展伴隨Linux從單處理器到對(duì)稱(chēng)多處理器的過(guò)度;伴隨著從非搶占內(nèi)核到搶占內(nèi)核的過(guò)度。鎖機(jī)制越來(lái)越有效,也越來(lái)越復(fù)雜。目前來(lái)說(shuō)內(nèi)核中原子操作多用來(lái)做計(jì)數(shù)使用,其它情況最常用的是兩種鎖以及它們的變種:一個(gè)是自旋鎖,另一個(gè)是信號(hào)量。

自旋鎖自旋鎖是專(zhuān)為防止多處理器并發(fā)而引入的一種鎖,它在內(nèi)核中大量應(yīng)用于中斷處理等部分(對(duì)于單處理器來(lái)說(shuō),防止中斷處理中的并發(fā)可簡(jiǎn)單采用關(guān)閉中斷的方式,不需要自旋鎖)。

自旋鎖最多只能被一個(gè)內(nèi)核任務(wù)持有,如果一個(gè)內(nèi)核任務(wù)試圖請(qǐng)求一個(gè)已被爭(zhēng)用(已經(jīng)被持有)的自旋鎖,那么這個(gè)任務(wù)就會(huì)一直進(jìn)行忙循環(huán)——旋轉(zhuǎn)——等待鎖重新可用。要是鎖未被爭(zhēng)用,請(qǐng)求它的內(nèi)核任務(wù)便能立刻得到它并且繼續(xù)進(jìn)行。自旋鎖可以在任何時(shí)刻防止多于一個(gè)的內(nèi)核任務(wù)同時(shí)進(jìn)入臨界區(qū),因此這種鎖可有效地避免多處理器上并發(fā)運(yùn)行的內(nèi)核任務(wù)競(jìng)爭(zhēng)共享資源。

自旋鎖的基本形式如下:

spin_lock(&mr_lock);//臨界區(qū)spin_unlock(&mr_lock);

·

信號(hào)量Linux中的信號(hào)量是一種睡眠鎖。如果有一個(gè)任務(wù)試圖獲得一個(gè)已被持有的信號(hào)量時(shí),信號(hào)量會(huì)將其推入等待隊(duì)列,然后讓其睡眠。這時(shí)處理器獲得自由去執(zhí)行其它代碼。當(dāng)持有信號(hào)量的進(jìn)程將信號(hào)量釋放后,在等待隊(duì)列中的一個(gè)任務(wù)將被喚醒,從而便可以獲得這個(gè)信號(hào)量。

信號(hào)量的睡眠特性,使得信號(hào)量適用于鎖會(huì)被長(zhǎng)時(shí)間持有的情況;只能在進(jìn)程上下文中使用,因?yàn)橹袛嗌舷挛闹惺遣荒鼙徽{(diào)度的;另外當(dāng)代碼持有信號(hào)量時(shí),不可以再持有自旋鎖。

信號(hào)量基本使用形式為:

staticDECLARE_MUTEX(mr_sem);//聲明互斥信號(hào)量if(down_interruptible(&mr_sem))//可被中斷的睡眠,當(dāng)信號(hào)來(lái)到,睡眠的任務(wù)被喚醒//臨界區(qū)up(&mr_sem);

信號(hào)量和自旋鎖區(qū)別從嚴(yán)格意義上說(shuō),信號(hào)量和自旋鎖屬于不同層次的互斥手段,前者的實(shí)現(xiàn)有賴(lài)于后者,在信號(hào)量本身的實(shí)現(xiàn)上,為了保證信號(hào)量結(jié)構(gòu)存取的原子性,在多CPU中需要自旋鎖來(lái)互斥。信號(hào)量是進(jìn)程級(jí)的。用于多個(gè)進(jìn)程之間對(duì)資源的互斥,雖然也是在內(nèi)核中,但是該內(nèi)核執(zhí)行路徑是以進(jìn)程的身份,代表進(jìn)程來(lái)爭(zhēng)奪進(jìn)程。鑒于進(jìn)程上下文切換的開(kāi)銷(xiāo)也很大,因此,只有當(dāng)進(jìn)程占用資源時(shí)間比較長(zhǎng)時(shí),用信號(hào)量才是較好的選擇。

當(dāng)所要保護(hù)的臨界區(qū)訪(fǎng)問(wèn)時(shí)間比較短時(shí),用自旋鎖是非常方便的,因?yàn)樗?jié)省上下文切換的時(shí)間,但是CPU得不到自旋鎖會(huì)在那里空轉(zhuǎn)直到執(zhí)行單元鎖為止,所以要求鎖不能在臨界區(qū)里長(zhǎng)時(shí)間停留,否則會(huì)降低系統(tǒng)的效率

由此,可以總結(jié)出自旋鎖和信號(hào)量選用的3個(gè)原則:

1:當(dāng)鎖不能獲取到時(shí),使用信號(hào)量的開(kāi)銷(xiāo)就是進(jìn)程上線(xiàn)文切換的時(shí)間Tc,使用自旋鎖的開(kāi)銷(xiāo)就是等待自旋鎖(由臨界區(qū)執(zhí)行的時(shí)間決定)Ts,如果Ts比較小時(shí),應(yīng)使用自旋鎖比較好,如果Ts比較大,應(yīng)使用信號(hào)量。

2:信號(hào)量所保護(hù)的臨界區(qū)可包含可能引起阻塞的代碼,而自旋鎖絕對(duì)要避免用來(lái)保護(hù)包含這樣的代碼的臨界區(qū),因?yàn)樽枞馕吨M(jìn)行進(jìn)程間的切換,如果進(jìn)程被切換出去后,另一個(gè)進(jìn)程企圖獲取本自旋鎖,死鎖就會(huì)發(fā)生。

3:信號(hào)量存在于進(jìn)程上下文,因此,如果被保護(hù)的共享資源需要在中斷或軟中斷情況下使用,則在信號(hào)量和自旋鎖之間只能選擇自旋鎖,當(dāng)然,如果一定要是要那個(gè)信號(hào)量,則只能通過(guò)down_trylock()方式進(jìn)行,不能獲得就立即返回以避免阻塞

自旋鎖VS信號(hào)量需求建議的加鎖方法低開(kāi)銷(xiāo)加鎖優(yōu)先使用自旋鎖短期鎖定優(yōu)先使用自旋鎖長(zhǎng)期加鎖優(yōu)先使用信號(hào)量中斷上下文中加鎖使用自旋鎖持有鎖是需要睡眠、調(diào)度使用信號(hào)量

20, 阻塞與非阻塞I/O

一個(gè)驅(qū)動(dòng)當(dāng)它無(wú)法立刻滿(mǎn)足請(qǐng)求應(yīng)當(dāng)如何響應(yīng)?一個(gè)對(duì) read 的調(diào)用可能當(dāng)沒(méi)有數(shù)據(jù)時(shí)到來(lái),而以后會(huì)期待更多的數(shù)據(jù);或者一個(gè)進(jìn)程可能試圖寫(xiě),但是你的設(shè)備沒(méi)有準(zhǔn)備好接受數(shù)據(jù),因?yàn)槟愕妮敵鼍彌_滿(mǎn)了。調(diào)用進(jìn)程往往不關(guān)心這種問(wèn)題,程序員只希望調(diào)用 read 或 write 并且使調(diào)用返回,在必要的工作已完成后,你的驅(qū)動(dòng)應(yīng)當(dāng)(缺省地)阻塞進(jìn)程,使它進(jìn)入睡眠直到請(qǐng)求可繼續(xù)。

阻塞操作是指在執(zhí)行設(shè)備操作時(shí)若不能獲得資源則掛起進(jìn)程,直到滿(mǎn)足可操作的條件后再進(jìn)行操作。

一個(gè)典型的能同時(shí)處理阻塞與非阻塞的globalfifo讀函數(shù)如下:

/*globalfifo讀函數(shù)*/

static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count,

loff_t *ppos)

{

int ret;

struct globalfifo_dev *dev =filp->private_data;

DECLARE_WAITQUEUE(wait, current);

down(&dev->sem); /* 獲得信號(hào)量 */

add_wait_queue(&dev->r_wait, &wait); /* 進(jìn)入讀等待隊(duì)列頭 */

/* 等待FIFO非空 */

if(dev->current_len ==0) {

if(filp->f_flags &O_NONBLOCK) {

ret =-EAGAIN;

goto out;

}

__set_current_state(TASK_INTERRUPTIBLE); /* 改變進(jìn)程狀態(tài)為睡眠 */

up(&dev->sem);

schedule(); /* 調(diào)度其他進(jìn)程執(zhí)行 */

if(signal_pending(current)) {

/* 如果是因?yàn)樾盘?hào)喚醒 */

ret =-ERESTARTSYS;

goto out2;

}

down(&dev->sem);

}

/* 拷貝到用戶(hù)空間 */

if(count >dev->current_len)

count =dev->current_len;

if(copy_to_user(buf, dev->mem, count)) {

ret =-EFAULT;

goto out;

} else{

memcpy(dev->mem, dev->mem +count, dev->current_len -count); /* fifo數(shù)據(jù)前移 */

dev->current_len -=count; /* 有效數(shù)據(jù)長(zhǎng)度減少 */

printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count, dev->current_len);

wake_up_interruptible(&dev->w_wait); /* 喚醒寫(xiě)等待隊(duì)列 */

ret =count;

}

out:

up(&dev->sem); /* 釋放信號(hào)量 */

out2:

remove_wait_queue(&dev->w_wait, &wait); /* 從附屬的等待隊(duì)列頭移除 */

set_current_state(TASK_RUNNING);

returnret;

}

21, poll方法

使用非阻塞I/O的應(yīng)用程序通常會(huì)使用select()和poll()系統(tǒng)調(diào)用查詢(xún)是否可對(duì)設(shè)備進(jìn)行無(wú)阻塞的訪(fǎng)問(wèn)。select()和poll()系統(tǒng)調(diào)用最終會(huì)引發(fā)設(shè)備驅(qū)動(dòng)中的poll()函數(shù)被執(zhí)行。這個(gè)方法由下列的原型:

unsigned int (*poll) (struct file *filp, poll_table *wait);

這個(gè)驅(qū)動(dòng)方法被調(diào)用, 無(wú)論何時(shí)用戶(hù)空間程序進(jìn)行一個(gè) poll, select, 或者 epoll 系統(tǒng)調(diào)用, 涉及一個(gè)和驅(qū)動(dòng)相關(guān)的文件描述符. 這個(gè)設(shè)備方法負(fù)責(zé)這 2 步:

1.對(duì)可能引起設(shè)備文件狀態(tài)變化的等待隊(duì)列,調(diào)用poll_wait()函數(shù),將對(duì)應(yīng)的等待隊(duì)列頭添加到poll_table.

2.返回一個(gè)位掩碼, 描述可能不必阻塞就立刻進(jìn)行的操作.

poll_table結(jié)構(gòu), 給 poll 方法的第 2 個(gè)參數(shù), 在內(nèi)核中用來(lái)實(shí)現(xiàn) poll, select, 和 epoll 調(diào)用; 它在 中聲明, 這個(gè)文件必須被驅(qū)動(dòng)源碼包含. 驅(qū)動(dòng)編寫(xiě)者不必要知道所有它內(nèi)容并且必須作為一個(gè)不透明的對(duì)象使用它; 它被傳遞給驅(qū)動(dòng)方法以便驅(qū)動(dòng)可用每個(gè)能喚醒進(jìn)程的等待隊(duì)列來(lái)加載它, 并且可改變 poll 操作狀態(tài). 驅(qū)動(dòng)增加一個(gè)等待隊(duì)列到poll_table結(jié)構(gòu)通過(guò)調(diào)用函數(shù)poll_wait:

void poll_wait (struct file *, wait_queue_head_t *, poll_table *);

poll 方法的第 2 個(gè)任務(wù)是返回位掩碼, 它描述哪個(gè)操作可馬上被實(shí)現(xiàn); 這也是直接的. 例如, 如果設(shè)備有數(shù)據(jù)可用, 一個(gè)讀可能不必睡眠而完成; poll 方法應(yīng)當(dāng)指示這個(gè)時(shí)間狀態(tài). 幾個(gè)標(biāo)志(通過(guò) 定義)用來(lái)指示可能的操作:POLLIN:如果設(shè)備可被不阻塞地讀, 這個(gè)位必須設(shè)置.POLLRDNORM:這個(gè)位必須設(shè)置, 如果”正常”數(shù)據(jù)可用來(lái)讀. 一個(gè)可讀的設(shè)備返回(POLLIN|POLLRDNORM).POLLOUT:這個(gè)位在返回值中設(shè)置, 如果設(shè)備可被寫(xiě)入而不阻塞.……poll的一個(gè)典型模板如下:

staticunsignedintglobalfifo_poll(structfile *filp, poll_table *wait)

{

unsignedintmask = 0;

structglobalfifo_dev *dev = filp->private_data; /*獲得設(shè)備結(jié)構(gòu)體指針*/

down(&dev->sem);

poll_wait(filp, &dev->r_wait, wait);

poll_wait(filp, &dev->w_wait, wait);

/*fifo非空*/

if(dev->current_len != 0) {

mask |= POLLIN | POLLRDNORM; /*標(biāo)示數(shù)據(jù)可獲得*/

}

/*fifo非滿(mǎn)*/

if(dev->current_len != GLOBALFIFO_SIZE) {

mask |= POLLOUT | POLLWRNORM; /*標(biāo)示數(shù)據(jù)可寫(xiě)入*/

}

up(&dev->sem);

returnmask;

}

應(yīng)用程序如何去使用這個(gè)poll呢?一般用select()來(lái)實(shí)現(xiàn),其原型為:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

其中,readfds, writefds, exceptfds,分別是被select()監(jiān)視的讀、寫(xiě)和異常處理的文件描述符集合。numfds是需要檢查的號(hào)碼最高的文件描述符加1。

以下是一個(gè)具體的例子:

/*======================================================================

A test program in userspace

This example is to introduce the ways to use "select"

and driver poll

The initial developer of the original code is Baohua Song

. All Rights Reserved.

======================================================================*/#include #include #include #include #include #include

#define FIFO_CLEAR 0x1#define BUFFER_LEN 20

main()

{

intfd, num;

charrd_ch[BUFFER_LEN];

fd_set rfds,wfds;

/*以非阻塞方式打開(kāi)/dev/globalmem設(shè)備文件*/

fd = open("/dev/globalfifo", O_RDONLY | O_NONBLOCK);

if(fd != - 1)

{

/*FIFO清0*/

if(ioctl(fd, FIFO_CLEAR, 0) < 0)

{

printf("ioctl command failed\n");

}

while(1)

{

FD_ZERO(&rfds);// 清除一個(gè)文件描述符集rfds

FD_ZERO(&wfds);

FD_SET(fd, &rfds);// 將一個(gè)文件描述符fd,加入到文件描述符集rfds中

FD_SET(fd, &wfds);

select(fd + 1, &rfds, &wfds, NULL, NULL);

/*數(shù)據(jù)可獲得*/

if(FD_ISSET(fd, &rfds)) //判斷文件描述符fd是否被置位

{

printf("Poll monitor:can be read\n");

}

/*數(shù)據(jù)可寫(xiě)入*/

if(FD_ISSET(fd, &wfds))

{

printf("Poll monitor:can be written\n");

}

}

}

else

{

printf("Device open failure\n");

}

}

其中:FD_ZERO(fd_set *set);//清除一個(gè)文件描述符集setFD_SET(int fd, fd_set *set);//將一個(gè)文件描述符fd,加入到文件描述符集set中FD_CLEAR(int fd, fd_set *set);//將一個(gè)文件描述符fd,從文件描述符集set中清除FD_ISSET(int fd, fd_set *set);//判斷文件描述符fd是否被置位。

22,并發(fā)與競(jìng)態(tài)介紹

Linux設(shè)備驅(qū)動(dòng)中必須解決一個(gè)問(wèn)題是多個(gè)進(jìn)程對(duì)共享資源的并發(fā)訪(fǎng)問(wèn),并發(fā)的訪(fǎng)問(wèn)會(huì)導(dǎo)致競(jìng)態(tài),在當(dāng)今的Linux內(nèi)核中,支持SMP與內(nèi)核搶占的環(huán)境下,更是充滿(mǎn)了并發(fā)與競(jìng)態(tài)。幸運(yùn)的是,Linux 提供了多鐘解決競(jìng)態(tài)問(wèn)題的方式,這些方式適合不同的應(yīng)用場(chǎng)景。例如:中斷屏蔽、原子操作、自旋鎖、信號(hào)量等等并發(fā)控制機(jī)制。

并發(fā)與競(jìng)態(tài)的概念并發(fā)是指多個(gè)執(zhí)行單元同時(shí)、并發(fā)被執(zhí)行,而并發(fā)的執(zhí)行單元對(duì)共享資源(硬件資源和軟件上的全局變量、靜態(tài)變量等)的訪(fǎng)問(wèn)則很容易導(dǎo)致競(jìng)態(tài)。

臨界區(qū)概念是為解決競(jìng)態(tài)條件問(wèn)題而產(chǎn)生的,一個(gè)臨界區(qū)是一個(gè)不允許多路訪(fǎng)問(wèn)的受保護(hù)的代碼,這段代碼可以操縱共享數(shù)據(jù)或共享服務(wù)。臨界區(qū)操縱堅(jiān)持互斥鎖原則(當(dāng)一個(gè)線(xiàn)程處于臨界區(qū)中,其他所有線(xiàn)程都不能進(jìn)入臨界區(qū))。然而,臨界區(qū)中需要解決的一個(gè)問(wèn)題是死鎖。

23, 中斷屏蔽

在單CPU 范圍內(nèi)避免競(jìng)態(tài)的一種簡(jiǎn)單而省事的方法是進(jìn)入臨界區(qū)之前屏蔽系統(tǒng)的中斷。CPU 一般都具有屏蔽中斷和打開(kāi)中斷的功能,這個(gè)功能可以保證正在執(zhí)行的內(nèi)核執(zhí)行路徑不被中斷處理程序所搶占,有效的防止了某些競(jìng)態(tài)條件的發(fā)送,總之,中斷屏蔽將使得中斷與進(jìn)程之間的并發(fā)不再發(fā)生。

中斷屏蔽的使用方法:

local_irq_disable() /屏蔽本地CPU 中斷/

…..

critical section /臨界區(qū)受保護(hù)的數(shù)據(jù)/

…..

local_irq_enable() /打開(kāi)本地CPU 中斷/

由于Linux 的異步I/O、進(jìn)程調(diào)度等很多重要操作都依賴(lài)于中斷,中斷對(duì)內(nèi)核的運(yùn)行非常重要,在屏蔽中斷期間的所有中斷都無(wú)法得到處理,因此長(zhǎng)時(shí)間屏蔽中斷是非常危險(xiǎn)的,有可能造成數(shù)據(jù)的丟失,甚至系統(tǒng)崩潰的后果。這就要求在屏蔽了中斷后,當(dāng)前的內(nèi)核執(zhí)行路徑要盡快地執(zhí)行完臨界區(qū)代碼。

與local_irq_disable()不同的是,local_irq_save(flags)除了進(jìn)行禁止中斷的操作外,還保存當(dāng)前CPU 的中斷狀態(tài)位信息;與local_irq_enable()不同的是,local_irq_restore(flags)除了打開(kāi)中斷的操作外,還恢復(fù)了CPU 被打斷前的中斷狀態(tài)位信息。

24, 原子操作

原子操作指的是在執(zhí)行過(guò)程中不會(huì)被別的代碼路徑所中斷的操作,Linux 內(nèi)核提供了兩類(lèi)原子操作——位原子操作和整型原子操作。它們的共同點(diǎn)是在任何情況下都是原子的,內(nèi)核代碼可以安全地調(diào)用它們而不被打斷。然而,位和整型變量原子操作都依賴(lài)于底層CPU 的原子操作來(lái)實(shí)現(xiàn),因此這些函數(shù)的實(shí)現(xiàn)都與 CPU 架構(gòu)密切相關(guān)。

1 整型原子操作1)、設(shè)置原子變量的值

voidatomic_set(atomic v,int i); /設(shè)置原子變量的值為 i */

atomic_t v = ATOMIC_INIT(0); /定義原子變量 v 并初始化為 0 /

2)、獲取原子變量的值

int atomic_read(atomic_t v) /返回原子變量 v 的當(dāng)前值*/

3)、原子變量加/減

void atomic_add(int i,atomic_t v) /原子變量增加 i */

void atomic_sub(int i,atomic_t v) /原子變量減少 i */

4)、原子變量自增/自減

void atomic_inc(atomic_t v) /原子變量增加 1 */

void atomic_dec(atomic_t v) /原子變量減少 1 */

5)、操作并測(cè)試

int atomic_inc_and_test(atomic_t *v);

int atomic_dec_and_test(atomic_t *v);

int atomic_sub_and_test(int i, atomic_t *v);

上述操作對(duì)原子變量執(zhí)行自增、自減和減操作后測(cè)試其是否為 0 ,若為 0 返回true,否則返回false。注意:沒(méi)有atomic_add_and_test(int i, atomic_t *v)。

6)、操作并返回

int atomic_add_return(int i, atomic_t *v);

int atomic_sub_return(int i, atomic_t *v);

int atomic_inc_return(atomic_t *v);

int atomic_dec_return(atomic_t *v);

上述操作對(duì)原子變量進(jìn)行加/減和自增/自減操作,并返回新的值。

2 位原子操作1)、設(shè)置位

void set_bit(nr,void addr);/設(shè)置addr 指向的數(shù)據(jù)項(xiàng)的第 nr 位為1 */

2)、清除位

void clear_bit(nr,void addr)/設(shè)置addr 指向的數(shù)據(jù)項(xiàng)的第 nr 位為0 */

3)、取反位

void change_bit(nr,void addr); /對(duì)addr 指向的數(shù)據(jù)項(xiàng)的第 nr 位取反操作*/

4)、測(cè)試位

test_bit(nr,void addr);/返回addr 指向的數(shù)據(jù)項(xiàng)的第 nr位*/

5)、測(cè)試并操作位

int test_and_set_bit(nr, void *addr);

int test_and_clear_bit(nr,void *addr);

int test_amd_change_bit(nr,void *addr);

25, 自旋鎖

自旋鎖(spin lock)是一種典型的對(duì)臨界資源進(jìn)行互斥訪(fǎng)問(wèn)的手段。為了獲得一個(gè)自旋鎖,在某CPU 上運(yùn)行的代碼需先執(zhí)行一個(gè)原子操作,該操作測(cè)試并設(shè)置某個(gè)內(nèi)存變量,由于它是原子操作,所以在該操作完成之前其他執(zhí)行單元不能訪(fǎng)問(wèn)這個(gè)內(nèi)存變量。如果測(cè)試結(jié)果表明鎖已經(jīng)空閑,則程序獲得這個(gè)自旋鎖并繼續(xù)執(zhí)行;如果測(cè)試結(jié)果表明鎖仍被占用,則程序?qū)⒃谝粋€(gè)小的循環(huán)里面重復(fù)這個(gè)“測(cè)試并設(shè)置” 操作,即進(jìn)行所謂的“自旋”。

理解自旋鎖最簡(jiǎn)單的方法是把它當(dāng)做一個(gè)變量看待,該變量把一個(gè)臨界區(qū)標(biāo)記為“我在這運(yùn)行了,你們都稍等一會(huì)”,或者標(biāo)記為“我當(dāng)前不在運(yùn)行,可以被使用”。

Linux中與自旋鎖相關(guān)操作有:1)、定義自旋鎖

spinlock_t my_lock;

2)、初始化自旋鎖

spinlock_t my_lock = SPIN_LOCK_UNLOCKED; /靜態(tài)初始化自旋鎖/

void spin_lock_init(spinlock_t lock); /動(dòng)態(tài)初始化自旋鎖*/

3)、獲取自旋鎖

/若獲得鎖立刻返回真,否則自旋在那里直到該鎖保持者釋放/

void spin_lock(spinlock_t *lock);

/若獲得鎖立刻返回真,否則立刻返回假,并不會(huì)自旋等待/

void spin_trylock(spinlock_t *lock)

4)、釋放自旋鎖

void spin_unlock(spinlock_t *lock)

自旋鎖的一般用法:

spinlock_t lock;/定義一個(gè)自旋鎖/

spin_lock_init(&lock);/動(dòng)態(tài)初始化一個(gè)自旋鎖/

……

spin_lock(&lock);/獲取自旋鎖,保護(hù)臨界區(qū)/

……./臨界區(qū)/

spin_unlock(&lock);/解鎖/

自旋鎖主要針對(duì)SMP 或單CPU 但內(nèi)核可搶占的情況,對(duì)于單CPU 且內(nèi)核不支持搶占的系統(tǒng),自旋鎖退化為空操作。盡管用了自旋鎖可以保證臨界區(qū)不受別的CPU和本地CPU內(nèi)的搶占進(jìn)程打擾,但是得到鎖的代碼路徑在執(zhí)行臨界區(qū)的時(shí)候,還可能受到中斷和底半部(BH)的影響,為了防止這種影響,就需要用到自旋鎖的衍生。

獲取自旋鎖的衍生函數(shù):

voidspin_lock_irq(spinlock_t lock); /獲取自旋鎖之前禁止中斷*/ voidspin_lock_irqsave(spinlock_t lock, unsigned longflags);/獲取自旋鎖之前禁止中斷,并且將先前的中斷狀態(tài)保存在flags 中*/ voidspin_lock_bh(spinlock_t lock); /在獲取鎖之前禁止軟中斷,但不禁止硬件中斷*/

釋放自旋鎖的衍生函數(shù):

void spin_unlock_irq(spinlock_t *lock)

void spin_unlock_irqrestore(spinlock_t *lock,unsigned long flags);

void spin_unlock_bh(spinlock_t *lock);

解鎖的時(shí)候注意要一一對(duì)應(yīng)去解鎖。自旋鎖注意點(diǎn):(1)自旋鎖實(shí)際上是忙等待,因此,只有占用鎖的時(shí)間極短的情況下,使用自旋鎖才是合理的。(2)自旋鎖可能導(dǎo)致系統(tǒng)死鎖。(3)自旋鎖鎖定期間不能調(diào)用可能引起調(diào)度的函數(shù)。如:copy_from_user()、copy_to_user()、kmalloc()、msleep()等函數(shù)。(4)擁有自旋鎖的代碼是不能休眠的。

26, 讀寫(xiě)自旋鎖

它允許多個(gè)讀進(jìn)程并發(fā)執(zhí)行,但是只允許一個(gè)寫(xiě)進(jìn)程執(zhí)行臨界區(qū)代碼,而且讀寫(xiě)也是不能同時(shí)進(jìn)行的。1)、定義和初始化讀寫(xiě)自旋鎖

rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* 靜態(tài)初始化 */

rwlock_t my_rwlock;

rwlock_init(&my_rwlock); /* 動(dòng)態(tài)初始化 */

2)、讀鎖定

voidread_lock(rwlock_t *lock); voidread_lock_irqsave(rwlock_t *lock, unsigned longflags); voidread_lock_irq(rwlock_t *lock); voidread_lock_bh(rwlock_t *lock);

3)、讀解鎖

voidread_unlock(rwlock_t *lock); voidread_unlock_irqrestore(rwlock_t *lock, unsigned longflags); voidread_unlock_irq(rwlock_t *lock); voidread_unlock_bh(rwlock_t *lock);

在對(duì)共享資源進(jìn)行讀取之前,應(yīng)該先調(diào)用讀鎖定函數(shù),完成之后調(diào)用讀解鎖函數(shù)。

4)、寫(xiě)鎖定

voidwrite_lock(rwlock_t *lock); voidwrite_lock_irqsave(rwlock_t *lock, unsigned longflags); voidwrite_lock_irq(rwlock_t *lock); voidwrite_lock_bh(rwlock_t *lock); voidwrite_trylock(rwlock_t *lock);

5)、寫(xiě)解鎖

voidwrite_unlock(rwlock_t *lock); voidwrite_unlock_irqrestore(rwlock_t *lock, unsigned longflags); voidwrite_unlock_irq(rwlock_t *lock); voidwrite_unlock_bh(rwlock_t *lock);

在對(duì)共享資源進(jìn)行寫(xiě)之前,應(yīng)該先調(diào)用寫(xiě)鎖定函數(shù),完成之后應(yīng)調(diào)用寫(xiě)解鎖函數(shù)。

讀寫(xiě)自旋鎖的一般用法:

rwlock_t lock;/定義一個(gè)讀寫(xiě)自旋鎖 rwlock/

rwlock_init(&lock);/初始化/

read_lock(&lock);/讀取前先獲取鎖/

…../臨界區(qū)資源/

read_unlock(&lock);/讀完后解鎖/

write_lock_irqsave(&lock, flags);/寫(xiě)前先獲取鎖/

…../臨界區(qū)資源/

write_unlock_irqrestore(&lock,flags);/寫(xiě)完后解鎖/

27, 順序鎖(sequence lock)

順序鎖是對(duì)讀寫(xiě)鎖的一種優(yōu)化,讀執(zhí)行單元在寫(xiě)執(zhí)行單元對(duì)被順序鎖保護(hù)的資源進(jìn)行寫(xiě)操作時(shí)仍然可以繼續(xù)讀,而不必等地寫(xiě)執(zhí)行單元完成寫(xiě)操作,寫(xiě)執(zhí)行單元也不必等待所有讀執(zhí)行單元完成讀操作才進(jìn)去寫(xiě)操作。但是,寫(xiě)執(zhí)行單元與寫(xiě)執(zhí)行單元依然是互斥的。并且,在讀執(zhí)行單元讀操作期間,寫(xiě)執(zhí)行單元已經(jīng)發(fā)生了寫(xiě)操作,那么讀執(zhí)行單元必須進(jìn)行重讀操作,以便確保讀取的數(shù)據(jù)是完整的,這種鎖對(duì)于讀寫(xiě)同時(shí)進(jìn)行概率比較小的情況,性能是非常好的。

順序鎖有個(gè)限制,它必須要求被保護(hù)的共享資源不包含有指針,因?yàn)閷?xiě)執(zhí)行單元可能使得指針失效,但讀執(zhí)行單元如果正要訪(fǎng)問(wèn)該指針,就會(huì)導(dǎo)致oops。

1)、初始化順序鎖

seqlock_t lock1 = SEQLOCK_UNLOCKED; /靜態(tài)初始化/

seqlock lock2; /動(dòng)態(tài)初始化/

seqlock_init(&lock2)

2)、獲取順序鎖

void write_seqlock(seqlock_t *s1);

void write_seqlock_irqsave(seqlock_t *lock, unsigned long flags)

void write_seqlock_irq(seqlock_t *lock);

void write_seqlock_bh(seqlock_t *lock); intwrite_tryseqlock(seqlock_t *s1);

3)、釋放順序鎖

void write_sequnlock(seqlock_t *s1);

void write_sequnlock_irqsave(seqlock_t *lock, unsigned long flags)

void write_sequnlock_irq(seqlock_t *lock);

void write_sequnlock_bh(seqlock_t *lock);

寫(xiě)執(zhí)行單元使用順序鎖的模式如下:

write_seqlock(&seqlock_a); /寫(xiě)操作代碼/

……..

write_sequnlock(&seqlock_a);

4)、讀開(kāi)始

unsignedread_seqbegin(constseqlock_t *s1); unsignedread_seqbegin_irqsave(seqlock_t *lock, unsignedlongflags);

5)、重讀

intread_seqretry(constseqlock_t *s1, unsignediv); intread_seqretry_irqrestore(seqlock_t *lock,unsignedintseq,unsignedlongflags);

讀執(zhí)行單元使用順序鎖的模式如下:

unsigned int seq; do{

seq = read_seqbegin(&seqlock_a);

/讀操作代碼/

…….

}while(read_seqretry(&seqlock_a, seq));

28, 信號(hào)量

信號(hào)量的使用信號(hào)量(semaphore)是用于保護(hù)臨界區(qū)的一種最常用的辦法,它的使用方法與自旋鎖是類(lèi)似的,但是,與自旋鎖不同的是,當(dāng)獲取不到信號(hào)量的時(shí)候,進(jìn)程不會(huì)自旋而是進(jìn)入睡眠的等待狀態(tài)。1)、定義信號(hào)量

struct semaphore sem;

2)、初始化信號(hào)量

void sema_init(struct semaphore sem, int val); /初始化信號(hào)量的值為 val */

更常用的是下面這二個(gè)宏:

#define init_MUTEX(sem) sema_init(sem, 1) #define init_MUTEX_LOCKED(sem) sem_init(sem, 0)

然而,下面這兩個(gè)宏是定義并初始化信號(hào)量的“快捷方式”

DECLARE_MUTEX(name) /一個(gè)稱(chēng)為name信號(hào)量變量被初始化為 1/

DECLARE_MUTEX_LOCKED(name) /一個(gè)稱(chēng)為name信號(hào)量變量被初始化為 0/

3)、獲得信號(hào)量

/該函數(shù)用于獲取信號(hào)量,若獲取不成功則進(jìn)入不可中斷的睡眠狀態(tài)/ voiddown(structsemaphore *sem);

/該函數(shù)用于獲取信號(hào)量,若獲取不成功則進(jìn)入可中斷的睡眠狀態(tài)/ voiddown_interruptible(structsemaphore *sem);

/該函數(shù)用于獲取信號(hào)量,若獲取不成功立刻返回 -EBUSY/ intdown_trylock(structsempahore *sem);

4)、釋放信號(hào)量

void up(struct semaphore sem); /釋放信號(hào)量 sem ,并喚醒等待者*/

信號(hào)量的一般用法:

DECLARE_MUTEX(mount_sem); /定義一個(gè)信號(hào)量mount_sem,并初始化為 1 /

down(&mount_sem); /* 獲取信號(hào)量,保護(hù)臨界區(qū)*/

…..

critical section /臨界區(qū)/

…..

up(&mount_sem); /釋放信號(hào)量/

29, 讀寫(xiě)信號(hào)量

讀寫(xiě)信號(hào)量可能引起進(jìn)程阻塞,但是它允許多個(gè)讀執(zhí)行單元同時(shí)訪(fǎng)問(wèn)共享資源,但最多只能有一個(gè)寫(xiě)執(zhí)行單元。1)、定義和初始化讀寫(xiě)信號(hào)量

struct rw_semaphore my_rws; /定義讀寫(xiě)信號(hào)量/

void init_rwsem(struct rw_semaphore sem); /初始化讀寫(xiě)信號(hào)量*/

2)、讀信號(hào)量獲取

void down_read(struct rw_semaphore *sem);

int down_read_trylock(struct rw_semaphore *sem);

3)、讀信號(hào)量釋放

void up_read(struct rw_semaphore *sem);

4)、寫(xiě)信號(hào)量獲取

void down_write(struct rw_semaphore *sem);

int down_write_trylock(struct rw_semaphore *sem);

5)、寫(xiě)信號(hào)量釋放

void up_write(struct rw_semaphore *sem);

30, completion

完成量(completion)用于一個(gè)執(zhí)行單元等待另外一個(gè)執(zhí)行單元執(zhí)行完某事。1)、定義完成量

struct completion my_completion;

2)、初始化完成量

init_completion(&my_completion);

3)、定義并初始化的“快捷方式”

DECLARE_COMPLETION(my_completion)

4)、等待完成量

void wait_for_completion(struct completion c); /等待一個(gè) completion 被喚醒*/

5)、喚醒完成量

void complete(struct completion c); /只喚醒一個(gè)等待執(zhí)行單元*/

void complete(struct completion c); /喚醒全部等待執(zhí)行單元*/

31, 自旋鎖VS信號(hào)量

信號(hào)量是進(jìn)程級(jí)的,用于多個(gè)進(jìn)程之間對(duì)資源的互斥,雖然也是在內(nèi)核中,但是該內(nèi)核執(zhí)行路徑是以進(jìn)程的身份,代表進(jìn)程來(lái)爭(zhēng)奪資源的。如果競(jìng)爭(zhēng)失敗,會(huì)發(fā)送進(jìn)程上下文切換,當(dāng)前進(jìn)程進(jìn)入睡眠狀態(tài),CPU 將運(yùn)行其他進(jìn)程。鑒于開(kāi)銷(xiāo)比較大,只有當(dāng)進(jìn)程資源時(shí)間較長(zhǎng)時(shí),選用信號(hào)量才是比較合適的選擇。然而,當(dāng)所要保護(hù)的臨界區(qū)訪(fǎng)問(wèn)時(shí)間比較短時(shí),用自旋鎖是比較方便的。

總結(jié):解決并發(fā)與競(jìng)態(tài)的方法有(按本文順序):

(1)中斷屏蔽(2)原子操作(包括位和整型原子)(3)自旋鎖(4)讀寫(xiě)自旋鎖(5)順序鎖(讀寫(xiě)自旋鎖的進(jìn)化)(6)信號(hào)量(7)讀寫(xiě)信號(hào)量(8)完成量

其中,中斷屏蔽很少單獨(dú)被使用,原子操作只能針對(duì)整數(shù)進(jìn)行,因此自旋鎖和信號(hào)量應(yīng)用最為廣泛。自旋鎖會(huì)導(dǎo)致死循環(huán),鎖定期間內(nèi)不允許阻塞,因此要求鎖定的臨界區(qū)?。恍盘?hào)量允許臨界區(qū)阻塞,可以適用于臨界區(qū)大的情況。讀寫(xiě)自旋鎖和讀寫(xiě)信號(hào)量分別是放寬了條件的自旋鎖 信號(hào)量,它們?cè)试S多個(gè)執(zhí)行單元對(duì)共享資源的并發(fā)讀。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5152

    文章

    19675

    瀏覽量

    317643
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11511

    瀏覽量

    213838

原文標(biāo)題:嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)基礎(chǔ)總結(jié)(下篇)

文章出處:【微信號(hào):gh_c472c2199c88,微信公眾號(hào):嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Linux嵌入式和單片機(jī)嵌入式的區(qū)別?

    新的應(yīng)用程序和驅(qū)動(dòng)程序來(lái)擴(kuò)展功能。 6. 開(kāi)發(fā)難度 : 單片機(jī)嵌入式開(kāi)發(fā)難度相對(duì)較低,適合初學(xué)者入門(mén)。 Linux
    發(fā)表于 06-20 09:46

    嵌入式開(kāi)發(fā)入門(mén)指南:從零開(kāi)始學(xué)習(xí)嵌入式

    基礎(chǔ) 3. 學(xué)習(xí)路徑推薦第一階段:熟悉開(kāi)發(fā)環(huán)境(如Keil、IAR、STM32)第二階段:掌握裸機(jī)編程與驅(qū)動(dòng)開(kāi)發(fā)第三階段:學(xué)習(xí)RTOS(實(shí)時(shí)操作系統(tǒng))如FreeRTOS第四階段:深入理解Lin
    發(fā)表于 05-15 09:29

    硬核升級(jí)!華清遠(yuǎn)見(jiàn)STM32MP157驅(qū)動(dòng)開(kāi)發(fā)課程助力嵌入式Linux底層開(kāi)發(fā)入門(mén)進(jìn)階

    嵌入式Linux系統(tǒng)開(kāi)發(fā)中,驅(qū)動(dòng)程序開(kāi)發(fā)是一項(xiàng)關(guān)鍵技術(shù),它作為硬件與軟件之間的橋梁,實(shí)現(xiàn)了操作系統(tǒng)對(duì)硬件設(shè)備的控制。相較于
    的頭像 發(fā)表于 04-03 16:40 ?431次閱讀
    硬核升級(jí)!華清遠(yuǎn)見(jiàn)STM32MP157<b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>開(kāi)發(fā)</b>課程助力<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>底層<b class='flag-5'>開(kāi)發(fā)</b>入門(mén)進(jìn)階

    嵌入式開(kāi)發(fā)必備-RK3562演示Linux常用系統(tǒng)查詢(xún)命令(上)觸覺(jué)智能出品

    實(shí)用干貨!嵌入式開(kāi)發(fā)學(xué)習(xí)必備-RK3562演示Linux常用系統(tǒng)查詢(xún)命令(上)關(guān)注觸覺(jué)智能持續(xù)為大家?guī)?lái)更多嵌入式開(kāi)發(fā)內(nèi)容
    的頭像 發(fā)表于 12-31 10:51 ?117次閱讀
    <b class='flag-5'>嵌入式開(kāi)發(fā)</b>必備-RK3562演示<b class='flag-5'>Linux</b>常用系統(tǒng)查詢(xún)命令(上)觸覺(jué)智能出品

    Made with KiCad(九十四):M5Pi Linux嵌入式開(kāi)發(fā)

    “ 波哥大作,必須優(yōu)先安排!M5Pi 是一款開(kāi)源 Linux 嵌入式開(kāi)發(fā)板,使用全志 F1C200s CPU,擁有漂亮的外殼?!?/div>
    的頭像 發(fā)表于 12-25 14:53 ?753次閱讀
    Made with KiCad(九十四):M5Pi <b class='flag-5'>Linux</b><b class='flag-5'>嵌入式開(kāi)發(fā)</b>板

    嵌入式 Linux 操作系統(tǒng)配置

    隨著物聯(lián)網(wǎng)(IoT)和智能設(shè)備的快速發(fā)展,嵌入式系統(tǒng)在各個(gè)領(lǐng)域扮演著越來(lái)越重要的角色。Linux因其開(kāi)源、靈活和穩(wěn)定的特性,成為嵌入式系統(tǒng)的首選操作系統(tǒng)。 1. 硬件選擇 在配置嵌入式
    的頭像 發(fā)表于 11-06 10:22 ?1204次閱讀

    【北京迅為】i.mx8mm嵌入式linux開(kāi)發(fā)指南第四篇 嵌入式Linux系統(tǒng)移植篇第六十九章uboot移植

    【北京迅為】i.mx8mm嵌入式linux開(kāi)發(fā)指南第四篇 嵌入式Linux系統(tǒng)移植篇第六十九章uboot移植
    的頭像 發(fā)表于 10-22 14:46 ?1167次閱讀
    【北京迅為】i.mx8mm<b class='flag-5'>嵌入式</b><b class='flag-5'>linux</b><b class='flag-5'>開(kāi)發(fā)</b>指南第四篇 <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>系統(tǒng)移植篇第六十九章uboot移植

    【免費(fèi)分享】嵌入式Linux開(kāi)發(fā)板【入門(mén)+項(xiàng)目,應(yīng)用+底層】資料包一網(wǎng)打盡,附教程/視頻/源碼...

    ?想要深入學(xué)習(xí)嵌入式Linux開(kāi)發(fā)嗎?現(xiàn)在機(jī)會(huì)來(lái)了!我們?yōu)槌鯇W(xué)者們準(zhǔn)備了一份全面的資料包,包括原理圖、教程、課件、視頻、項(xiàng)目、源碼等,所有資料全部免費(fèi)領(lǐng)取,課程視頻可試看(購(gòu)買(mǎi)后看完整版),讓你
    的頭像 發(fā)表于 09-05 10:45 ?622次閱讀
    【免費(fèi)分享】<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b><b class='flag-5'>開(kāi)發(fā)</b>板【入門(mén)+項(xiàng)目,應(yīng)用+底層】資料包一網(wǎng)打盡,附教程/視頻/源碼...

    北京迅為RK3568開(kāi)發(fā)嵌入式學(xué)習(xí)之Linux驅(qū)動(dòng)全新更新-CAN+

    北京迅為RK3568開(kāi)發(fā)嵌入式學(xué)習(xí)之Linux驅(qū)動(dòng)全新更新-CAN+
    的頭像 發(fā)表于 09-04 15:29 ?1049次閱讀
    北京迅為RK3568<b class='flag-5'>開(kāi)發(fā)</b>板<b class='flag-5'>嵌入式</b>學(xué)習(xí)之<b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動(dòng)</b>全新更新-CAN+

    【北京迅為】《stm32mp157開(kāi)發(fā)嵌入式linux開(kāi)發(fā)指南》第五章 Ubuntu使用apt-get下載

    【北京迅為】《stm32mp157開(kāi)發(fā)嵌入式linux開(kāi)發(fā)指南》第五章 Ubuntu使用apt-get下載
    的頭像 發(fā)表于 09-03 16:26 ?1180次閱讀
    【北京迅為】《stm32mp157<b class='flag-5'>開(kāi)發(fā)</b>板<b class='flag-5'>嵌入式</b><b class='flag-5'>linux</b><b class='flag-5'>開(kāi)發(fā)</b>指南》第五章 Ubuntu使用apt-get下載

    嵌入式linux開(kāi)發(fā)的基本步驟有哪些?

    嵌入式Linux開(kāi)發(fā)是一個(gè)復(fù)雜的過(guò)程,涉及到硬件選擇、操作系統(tǒng)移植、驅(qū)動(dòng)開(kāi)發(fā)、應(yīng)用程序開(kāi)發(fā)等多個(gè)
    的頭像 發(fā)表于 09-02 09:11 ?1254次閱讀

    嵌入式linux開(kāi)發(fā)板怎么操作

    嵌入式Linux開(kāi)發(fā)板是一種基于Linux操作系統(tǒng)的嵌入式系統(tǒng)開(kāi)發(fā)平臺(tái)。它通常包括一個(gè)處理器、內(nèi)
    的頭像 發(fā)表于 09-02 09:09 ?802次閱讀

    嵌入式linux開(kāi)發(fā)板芯片的工作原理

    嵌入式Linux開(kāi)發(fā)板是一種基于Linux操作系統(tǒng)的嵌入式系統(tǒng)開(kāi)發(fā)平臺(tái),它廣泛應(yīng)用于工業(yè)控制、智
    的頭像 發(fā)表于 09-02 09:07 ?821次閱讀

    【出版發(fā)行】嵌入式系統(tǒng)原理與開(kāi)發(fā)——基于RISC-V和Linux系統(tǒng)

    【出版發(fā)行】嵌入式系統(tǒng)原理與開(kāi)發(fā)——基于RISC-V和Linux系統(tǒng)
    的頭像 發(fā)表于 07-26 08:36 ?678次閱讀
    【出版發(fā)行】<b class='flag-5'>嵌入式</b>系統(tǒng)原理與<b class='flag-5'>開(kāi)發(fā)</b>——基于RISC-V和<b class='flag-5'>Linux</b>系統(tǒng)

    專(zhuān)家力薦|《嵌入式系統(tǒng)原理與開(kāi)發(fā)——基于RISC-V和Linux系統(tǒng)》新書(shū)發(fā)售

    當(dāng)前,嵌入式系統(tǒng)已成為智能設(shè)備的核心之一,RISC-V+Linux的開(kāi)源力量為嵌入式系統(tǒng)注入強(qiáng)大的創(chuàng)新動(dòng)力。作為中國(guó)RISC-V軟硬件生態(tài)領(lǐng)導(dǎo)者,賽昉科技與業(yè)界專(zhuān)家合作推出《嵌入式系統(tǒng)
    的頭像 發(fā)表于 07-24 08:20 ?1107次閱讀
    專(zhuān)家力薦|《<b class='flag-5'>嵌入式</b>系統(tǒng)原理與<b class='flag-5'>開(kāi)發(fā)</b>——基于RISC-V和<b class='flag-5'>Linux</b>系統(tǒng)》新書(shū)發(fā)售