日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > 互聯(lián)網(wǎng) > 《Linux Device Drivers》第六章 高級(jí)字符驅(qū)動(dòng)程序操作――note

《Linux Device Drivers》第六章 高級(jí)字符驅(qū)動(dòng)程序操作――note

來(lái)源:程序員人生   發(fā)布時(shí)間:2014-10-11 08:00:01 閱讀次數(shù):2225次
  • ioctl
    • 支持的操作,例如
      • 簡(jiǎn)單數(shù)據(jù)傳輸
      • 控制動(dòng)作,例如用戶(hù)空間發(fā)起彈出介質(zhì)動(dòng)作
      • 反饋硬件的狀態(tài),例如報(bào)告錯(cuò)誤信息
      • 參數(shù)配置,例如改變波特率
      • 執(zhí)行自破壞
    • 用戶(hù)空間的ioctl方法原型:int ioctl(int fd, unsigned long cmd, …);每個(gè)ioctl命令就是一個(gè)獨(dú)立的系統(tǒng)調(diào)用,而且是非公開(kāi)的
    • 驅(qū)動(dòng)程序的ioctl方法原型:int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
    • 選擇ioctl命令
      • 為方便程序員創(chuàng)建唯一的ioctl命令號(hào),每一個(gè)命令號(hào)被分為多個(gè)位字段
      • Linux內(nèi)核的約定方法為驅(qū)動(dòng)程序選擇ioctl編號(hào)
        • include/asm/ioctl.h
          • 定義了要使用的位字段
            • 類(lèi)型(幻數(shù))
            • 序數(shù)
            • 傳送方向
            • 參數(shù)大小
        • Documentation/ioctl-number.txt
          • 羅列了內(nèi)核所使用的幻數(shù)
      • <linux/ioctl.h>
        • type
          • 幻數(shù),這個(gè)字段有8位寬(_IOC_TYPEBITS)
        • number
          • 序數(shù),8位寬(_IOC_NRBITS)
        • direction
          • _IOC_NONE(沒(méi)有數(shù)據(jù)傳輸)
          • _IOC_READ
          • _IOC_WRITE
          • _IOC_READ | _IOC_WRITE(雙向傳輸數(shù)據(jù))
        • size
          • 所涉及的用戶(hù)數(shù)據(jù)大小
          • 通常是13位或14位
          • _IOC_SIZEBITS
      • <asm/ioctl.h>
        • _IO(type, nr)
          • 用于構(gòu)造無(wú)參數(shù)的命令編號(hào)
        • _IOR(type, nr, datatype)
          • 用于構(gòu)造從驅(qū)動(dòng)程序中讀取數(shù)據(jù)的命令編號(hào)
        • _IOW(type, nr, datatype)
          • 用于構(gòu)造寫(xiě)入數(shù)據(jù)的命令
        • _IOWR(type, nr, datatype)
          • 用于雙向傳輸
        • _IOC_DIR(nr)
        • _IOC_TYPE(nr);
        • _IOC_NR(nr)
        • _IOC_SIZE(nr);
    • 返回值
      • ioctl的實(shí)現(xiàn)通常就是一個(gè)基于命令號(hào)的switch語(yǔ)句
      • 不能匹配任何合法的操作?
        • 有些內(nèi)核函數(shù)會(huì)返回-EINVAL
        • POSIX標(biāo)準(zhǔn)規(guī)定,如果使用了不合適的ioctl命令參數(shù),應(yīng)該返回-ENOTTY
    • 預(yù)定義命令
      • 預(yù)定義命令分為三組
        • 可用于任何文件(普通、設(shè)備、FIFO和套接字)的命令
        • 只用于普通文件的命令
        • 特定于文件系統(tǒng)類(lèi)型的命令
      • 設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)人員只對(duì)第一組感興趣,它們的幻數(shù)都是“T”
      • FIOCLEX
        • 設(shè)置執(zhí)行時(shí)關(guān)閉標(biāo)志
      • FIONCLEX
        • 清除執(zhí)行時(shí)關(guān)閉標(biāo)志
      • FIOASYNC
        • 設(shè)置或復(fù)位文件異步通知
        • 這兩個(gè)動(dòng)作都可以通過(guò)fcntl完成,實(shí)際上沒(méi)有人會(huì)使用FIOASYNC
      • FIOQSIZE
        • 返回文件或目錄的大小
      • FIONBIO
        • 文件ioctl非阻塞型I/O
    • 使用ioctl參數(shù)
      • <asm/uaccess.h>
        • int access_ok(int type, const void *addr, unsigned long size);
        • type
          • VERIFY_READ
          • VERIFY_WRITE
        • addr
          • 用戶(hù)地址空間
        • size
          • 字節(jié)數(shù)
        • 返回一個(gè)布爾值:1表示成功,0表示失敗
        • 如果返回失敗,驅(qū)動(dòng)程序通常要返回-EFAULT給調(diào)用者
        • put_user(datum, ptr);
        • __put_user(datum, ptr);
        • get_user(local, ptr);
        • __get_user(local, ptr);
    • 權(quán)能與受限操作
      • 基于權(quán)能(capability)的系統(tǒng)把特權(quán)操作劃分為獨(dú)立的組
      • capget
      • capset
      • <linux/capability.h>
        • CAP_DAC_OVERRIDE
          • 超過(guò)文件或目錄的訪(fǎng)問(wèn)限制的能力
        • CAP_NET_ADMIN
          • 執(zhí)行網(wǎng)絡(luò)管理任何的能力
        • CAP_SYS_MODULE
          • 載入或卸除內(nèi)核模塊的能力
        • CAP_SYS_RAWIO
          • 執(zhí)行“裸”I/O操作的能力
        • CAP_SYS_ADMIN
          • 截獲的能力
        • CAP_SYS_TTY_CONFIG
          • 執(zhí)行tty配置任務(wù)的能力
      • <sys/sched.h>
        • int capable(int capability);

  • 阻塞型I/O
    • 休眠的簡(jiǎn)單介紹
      • 當(dāng)一個(gè)進(jìn)程被置入休眠時(shí),它會(huì)被標(biāo)記為一種特殊狀態(tài)并從調(diào)度器的運(yùn)行隊(duì)列中移走
      • 永遠(yuǎn)不要在原子上下文中進(jìn)入休眠
      • 如果代碼在擁有信號(hào)量時(shí)休眠,任何其他等待該信號(hào)量的線(xiàn)程也會(huì)休眠,因此任何擁有信號(hào)量而休眠的代碼必須很短,并且還要確保擁有信號(hào)量并不會(huì)阻塞喚醒我們自己的那個(gè)進(jìn)程
      • 當(dāng)我們被喚醒時(shí),我們永遠(yuǎn)無(wú)法知道休眠了多長(zhǎng)時(shí)間,或者休眠期間都發(fā)生了些什么事情
      • 在Linux中,一個(gè)等待隊(duì)列通過(guò)一個(gè)“等待隊(duì)列頭(wait queue head)”來(lái)管理
        • <linux/wait.h>
        • wait_queue_head_t
        • DECLARE_WAIT_QUEUE_HEAD(name);
        • wait_queue_head_t my_queue;
        • init_waitqueue_head(&my_queue);
    • 簡(jiǎn)單休眠
      • wait_event(queue, condition);
      • wait_event_interruptible(queue, condition);
      • wait_event_timeout(queue, condition, timeout);
      • wait_event_interruptible_timeout(queue, condition, timeout);
      • void wake_up(wait_queue_head_t *queue);
      • void wake_up_interruptible(wait_queue_head_t *queue);
    • 阻塞和非阻塞型操作
      • 顯式的非阻塞I/O由filp->f_flags中的O_NONBLOCK標(biāo)志決定
      • <linux/fcntl.h>
        • 自動(dòng)包含在<linux/fs.h>中
      • 在執(zhí)行阻塞型操作的情況下,應(yīng)該實(shí)現(xiàn)下列動(dòng)作以保持和標(biāo)準(zhǔn)語(yǔ)義一致
        • 如果一個(gè)進(jìn)程調(diào)用了read但是還沒(méi)有數(shù)據(jù)可讀,此進(jìn)程必須阻塞
        • 如果一個(gè)進(jìn)程調(diào)用了write但緩沖區(qū)沒(méi)有空間,此進(jìn)程必須阻塞,而且必須休眠在與讀取進(jìn)程不同的等待隊(duì)列上
    • 高級(jí)休眠
      • 進(jìn)程如何休眠
        • 將進(jìn)程置于休眠的第一個(gè)步驟通常是分配并初始化一個(gè)wait_queue_t結(jié)構(gòu),然后將其加入到對(duì)應(yīng)的等待隊(duì)列
        • 第二個(gè)步驟是設(shè)置進(jìn)程的狀態(tài),將其標(biāo)記為休眠
          • <linux/sched.h>
          • TASK_RUNNING
          • TASK_INTERRUPTIBLE
          • TASK_UNINTERRUPUTIBLE
          • void set_current_state(int new_state);
        • 放棄處理器是最后的步驟,但在此之前還要做另外一件事情:我們必須首先檢查休眠等待的條件
          • if (!condition) schedule();
      • 手工休眠
        • <linux/sched.h>
        • DEFINE_WAIT(my_wait);
        • wait_queue_t my_wait;
        • init_wait(&my_wait);
        • void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
          • state是進(jìn)程的新?tīng)顟B(tài),應(yīng)該是TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE
        • schedule();
        • void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);
      • 獨(dú)占等待
        • 當(dāng)某個(gè)進(jìn)程在等待隊(duì)列上調(diào)用wake_up時(shí),所有等待在該隊(duì)列上的進(jìn)程都被置為可運(yùn)行狀態(tài)
        • 只會(huì)有一個(gè)被喚醒的進(jìn)程可以獲得期望的資源,而其他被喚醒的進(jìn)程只會(huì)再次休眠
        • 一個(gè)獨(dú)占等待的行為和通常的休眠類(lèi)似,但有如下兩個(gè)重要的不同
          • 等待隊(duì)列入口設(shè)置了WQ_FLAG_EXCLUSIVE標(biāo)志時(shí),則會(huì)被添加到等待隊(duì)列的尾部
          • 在某個(gè)等待隊(duì)列上調(diào)用wake_up時(shí),它會(huì)在喚醒第一個(gè)具有WQ_FLAG_EXCLUSIVE標(biāo)志的進(jìn)程之后停止喚醒其他進(jìn)程
        • 如果滿(mǎn)足下面兩個(gè)條件,在驅(qū)動(dòng)程序中利用獨(dú)占等待是值得考慮的
          • 對(duì)某個(gè)資源存在嚴(yán)重競(jìng)爭(zhēng),并且喚醒單個(gè)進(jìn)程就能完整消耗該資源
        • void prepare_to_wait_exclusive(wait_queue_head_t *queue, wait_queue_t *wait, int state);
      • 喚醒的相關(guān)細(xì)節(jié)
        • <linux/wait.h>
        • wake_up(wait_queue_head_t *queue);
          • 喚醒隊(duì)列上所有非獨(dú)占等待的進(jìn)程,以及單個(gè)獨(dú)占等待者
        • wake_up_interruptible(wait_queue_head_t *queue);
          • 會(huì)跳過(guò)不可中斷休眠的那些進(jìn)程
        • wake_up_nr(wait_queue_head_t *queue, int nr);
          • 只會(huì)喚醒nr個(gè)獨(dú)占等待進(jìn)程
        • wake_up_interruptible_nr(wait_queue_head_t *queue, int nr);
          • 只會(huì)喚醒nr個(gè)獨(dú)占等待進(jìn)程
        • wake_up_all(wait_queue_head_t *queue);
        • wake_up_interruptible_all(wait_queue_head_t *queue);
        • wake_up_interruptible_sync(wait_queue_head_t *queue);
      • 舊的歷史:sleep_on
        • void sleep_on(wait_queue_head_t *queue);
        • void interruptible_sleep_on(wait_queue_head_t *queue);
        • 永遠(yuǎn)不要使用它們
  • poll和select
    • poll、select和epoll系統(tǒng)調(diào)用
    • poll、select和epoll的功能本質(zhì)上是一樣的:都允許進(jìn)程決定是否可以對(duì)一個(gè)或多個(gè)打開(kāi)的文件做非阻塞的讀取或?qū)懭?/li>
    • select在BSD Unix中引入
    • poll由System V引入
    • unsigned int (*poll) (struct file *filp, poll_table *wait);
    • poll_table結(jié)構(gòu),用于在內(nèi)核中實(shí)現(xiàn)poll、select及epool系統(tǒng)調(diào)用
    • <linux/poll.h>
    • void poll_wait(struct file *, wait_queue_head_t *, poll_table *);
    • poll方法執(zhí)行的第二項(xiàng)任務(wù)是返回描述哪個(gè)操作可以立即執(zhí)行的位掩碼
      • <linux/poll.h>
      • POLLIN
        • 如果設(shè)備可以無(wú)阻塞地讀取,就設(shè)置該位
      • POLLRDNORM
        • 如果“通常”的數(shù)據(jù)已經(jīng)就緒,可以讀取,就設(shè)置該位
        • 一個(gè)可讀設(shè)備返回(POLLIN|POLLRDNORM)
      • POLLRDBAND
        • 這一位指示可以從設(shè)備讀取out-of-band的數(shù)據(jù)
      • POLLPRI
        • 可以無(wú)阻塞地讀取高優(yōu)先級(jí)的數(shù)據(jù)
      • POLLHUP
        • 當(dāng)讀取設(shè)備的進(jìn)程到達(dá)文件尾時(shí),驅(qū)動(dòng)程序必須設(shè)置POLLHUP位
      • POLLERR
        • 設(shè)備發(fā)生了錯(cuò)誤
      • POLLOUT
        • 如果設(shè)備可以無(wú)阻塞地寫(xiě)入,就在返回值中設(shè)置該位
      • POLLWRNORM
        • 該位和POLLOUT的意義一樣,有時(shí)其實(shí)就是同一個(gè)數(shù)字
        • 一個(gè)可寫(xiě)的設(shè)備將返回(POLLOUT|POLLWRNORM)
      • POLLWRBAND
        • 與POLLRDBAND類(lèi)似,這一位表示具有非零優(yōu)先級(jí)的數(shù)據(jù)可以被寫(xiě)入設(shè)備
      • POLLRDBAND和POLLWRBAND只在與套接字相關(guān)的文件描述符中才是有意義的,設(shè)備驅(qū)動(dòng)程序通常用不到這兩個(gè)標(biāo)志
    • 與read和write的交互
      • 從設(shè)備讀取數(shù)據(jù)
        • 如果輸入緩沖區(qū)有數(shù)據(jù),那么即使就緒的數(shù)據(jù)比程序所請(qǐng)求的少,并且驅(qū)動(dòng)程序保證剩下的數(shù)據(jù)馬上就能到達(dá),read調(diào)用仍然應(yīng)該以難以察覺(jué)的延遲立即返回
        • 如果緩沖區(qū)中沒(méi)有數(shù)據(jù),那么默認(rèn)情況下read必須阻塞等待,直到至少有一個(gè)字節(jié)到達(dá);如果設(shè)置了O_NONBLOCK標(biāo)志,read應(yīng)立即返回,返回值是-EAGAIN。poll必須報(bào)告設(shè)備不可讀
        • 如果已經(jīng)到達(dá)文件尾,read應(yīng)該立即返回0,此時(shí)poll應(yīng)該報(bào)告POLLHUP
      • 向設(shè)備寫(xiě)數(shù)據(jù)
        • 如果輸出緩沖區(qū)中有空間,則write應(yīng)該無(wú)延遲地立即返回,在這種情況下,poll報(bào)告設(shè)備可寫(xiě)
        • 如果輸出緩沖區(qū)已滿(mǎn),那么默認(rèn)情況下write被阻塞直到有空間釋放;如果設(shè)置了O_NONBLOCK標(biāo)志,write應(yīng)立即返回,返回值是-EAGAIN。poll必須報(bào)告設(shè)備不可寫(xiě)
        • 永遠(yuǎn)不要讓write調(diào)用在返回前等待數(shù)據(jù)的傳輸結(jié)束
      • 刷新待處理輸出
        • int (*fsync) (struct file *file, struct dentry *dentry, int datasync);
        • 如果應(yīng)用程序需要確保數(shù)據(jù)已經(jīng)被傳送到設(shè)備上,就必須fsync方法
        • datasync用于區(qū)分fsync和fdatasync這兩個(gè)系統(tǒng)調(diào)用
    • 底層的數(shù)據(jù)結(jié)構(gòu)
      • poll_table結(jié)構(gòu)是構(gòu)成實(shí)際數(shù)據(jù)結(jié)構(gòu)的一個(gè)簡(jiǎn)單封裝,包含poll_table_entry結(jié)構(gòu)的內(nèi)存頁(yè)鏈表
      • 每個(gè)poll_table_entry結(jié)構(gòu)包括一個(gè)指向被打開(kāi)設(shè)備的struct file類(lèi)型的指針、一個(gè)wait_queue_head_t指針以及一個(gè)關(guān)聯(lián)的等待隊(duì)列入口
      • 如果輪詢(xún)(poll)時(shí)沒(méi)有一個(gè)驅(qū)動(dòng)程序可以進(jìn)行非阻塞I/O,這個(gè)poll調(diào)用者就進(jìn)入休眠,直到休眠在其上的某個(gè)(或多個(gè))等待隊(duì)列喚醒它為止
      • poll實(shí)現(xiàn)中的珍上有趣之處是,驅(qū)動(dòng)程序的poll方法在被調(diào)用者時(shí)為plol_table參數(shù)傳遞NULL指針。
      • 在poll調(diào)用結(jié)束時(shí),poll_table結(jié)構(gòu)被重新分配,所有的先前添加到poll表中的等待隊(duì)列入口都會(huì)從這個(gè)表以及等待隊(duì)列中移除
  • 異步通知
    • 為了啟用文件袋異步通知機(jī)制,用戶(hù)程序必須執(zhí)行兩個(gè)步驟
      • 首先,它們指定一個(gè)進(jìn)程作為文件的屬主,當(dāng)進(jìn)程使用fcntl系統(tǒng)調(diào)用執(zhí)行F_SETOWN命令時(shí),屬主進(jìn)程的進(jìn)程ID號(hào)就被保存在filp->f_owner中
      • 然后,用戶(hù)程序必須在設(shè)備中設(shè)備FASYNC標(biāo)志,通過(guò)fcntl的F_SETFL命令完成的
    • 例子
      • struct sigaction action;
      • memset(&action, 0, sizeof(action));
      • action.sa_handler = sighandler;
      • action.sa_flags = 0;
      • sigaction(SIGIO, &action, NULL);
      • fcntl(STDIN_FILENO, F_SETOWN, getpid());
      • oflags = fcntl(STDIN_FILENO, F_GETFL);
      • fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
    • 從驅(qū)動(dòng)程序的角度考慮
      • 從內(nèi)核角度來(lái)看的詳細(xì)操作過(guò)程
        • F_SETOWN被調(diào)用時(shí)對(duì)filp->f_owner賦值,此外什么也不做
        • 在執(zhí)行F_SETFL啟用FASYNC時(shí),調(diào)用驅(qū)動(dòng)程序的fasync方法,只要filp->f_flags中的FASYNC標(biāo)志發(fā)生了變化,就會(huì)調(diào)用該方法,以便把這個(gè)變化通知驅(qū)動(dòng)程序,使其能正確響應(yīng)
        • 當(dāng)數(shù)據(jù)到達(dá)時(shí),所有注冊(cè)為異步通知的進(jìn)程都會(huì)被發(fā)送一個(gè)SIGIO信號(hào)
      • <linux/fs.h>
      • struct fasync_struct
      • int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
      • void kill_fasync(struct fasync_struct **fa, int sig, int band);
        • sig通常是SIGIO
        • band通常是POLL_IN,等價(jià)于POLLIN|POLLRDNORM
      • 某些設(shè)備也針對(duì)設(shè)備可寫(xiě)入而實(shí)現(xiàn)了異步通知,在這種情況下,kill_fasync必須以POLL_OUT為模式調(diào)用
      • 當(dāng)文件關(guān)閉時(shí)必須的調(diào)用fasync方法
  • 定位設(shè)備
    • llseek實(shí)現(xiàn)
      • 如果設(shè)備操作未定義llseek方法,內(nèi)核默認(rèn)通過(guò)修改filp->f_pos而執(zhí)行定位
      • 如果定位操作對(duì)應(yīng)于設(shè)備的一個(gè)物理操作,可能就需要提供自己的llseek方法
      • 如果定位設(shè)備是沒(méi)有意義的,應(yīng)該在open方法中調(diào)用nonseekable_open,通知內(nèi)核設(shè)備不支持llseek
      • int nonseekable_open(struct inode *inode, struct file *filp);
      • 還應(yīng)該將file_operations結(jié)構(gòu)中的llseek方法設(shè)置為特殊的輔助函數(shù)no_llseek
  • 設(shè)備文件的訪(fǎng)問(wèn)控制
    • 獨(dú)享設(shè)備
      • 最生硬的訪(fǎng)問(wèn)控制方法是一次只允許一個(gè)進(jìn)程打開(kāi)設(shè)備
    • 限制每次只由一個(gè)用戶(hù)訪(fǎng)問(wèn)
      • 需要兩個(gè)數(shù)據(jù)項(xiàng)
        • 一個(gè)打開(kāi)計(jì)數(shù)
        • 設(shè)備屬主的UID
      • current->uid
      • current->euid
    • 替代EBUSY的阻塞型open
      • 當(dāng)設(shè)備不能訪(fǎng)問(wèn)時(shí)返回一個(gè)錯(cuò)誤,通常這是最合理的方式,但有些情況下可能需要讓進(jìn)程等待設(shè)備
    • 在打開(kāi)時(shí)復(fù)制設(shè)備
      • 另一個(gè)實(shí)現(xiàn)訪(fǎng)問(wèn)控制的方法是,在進(jìn)程打開(kāi)設(shè)備時(shí)創(chuàng)建設(shè)備的不同私有副本
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線(xiàn)----------------------------
分享到:
------分隔線(xiàn)----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲xxxx做受欧美 | 欧美日韩精品电影 | 狠狠色狠狠色综合人人 | 日韩久 | 免费一级淫片aaa片毛片a级 | 国产大片在线观看 | 欧美伊人精品成人久久综合97 | a在线免费 | 久久久在线 | 国产精品久久久av | 中文字幕一区二区三区在线播放 | 久久香视频 | 精品久久久久久国产 | 国产精品一区二 | 在线观看国产小视频 | 亚洲一区二区三区在线免费观看 | 白色丝袜美女羞羞av | 亚洲成人av一区二区三区 | 国产精品不卡在线 | 亚洲欧美视频在线观看 | 成人久久网 | 国产一区二区在线视频观看 | 亚洲青涩网 | 国产99re| 一级毛片观看 | 国产精品久久久久久久久久久新郎 | 欧美一区二区精品久久久 | 日本暖暖在线视频 | 日韩视频免费在线观看 | 国产精品亚洲视频 | 色婷婷狠 | 日韩在线视频一区 | 亚洲成人一区二区 | 精品在线不卡 | 在线观看视频一区 | 欧美一区二区三区影视 | 国产成人免费片在线观看 | 正在播放国产一区 | 黄色免费视频在线观看 | 国产视频久久 | 国产精品不卡一区二区三区 |