国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
讀取proc文件之seq

本文也即《Linux Device Drivers》,LDD3的第四章Debuging Techniques的讀書筆記之三,但我們不限于此內(nèi)容。

  在上次我們使用了read_proc的方式通過(guò)/proc文件讀取kernel module的信息。作者給的例子他自己說(shuō)是ugly。而我們?cè)谧x取大量數(shù)據(jù)時(shí)發(fā)現(xiàn),受到用戶buffer大小的限制(page的大?。?,可能需要讀取多次,不僅需要記錄上次讀取的位置,而且由于每次讀取我們申請(qǐng)了信號(hào)量,讀取完釋放,那么如果多次讀取的間隔中,如果信號(hào)量被寫所獲取就好出現(xiàn)混亂。linux kernel提供seq_file更好的方式來(lái)解決這個(gè)問(wèn)題,除非我們確定讀取的信息量非常少,能夠在page中返回,我們應(yīng)使用seq_file的方式而不是read_proc 。

  LDD3中介紹的方式,我覺(jué)得是典型的西方人和中國(guó)人思維方式的不同。在seq_file的介紹中,LDD3先從每個(gè)操作具體將其,然后到如何和proc文件聯(lián)系,最后到如何創(chuàng)建proc文件,我喜歡反過(guò)來(lái)的方式,先創(chuàng)建proc,在一步步細(xì)化。老外是日月年,我們是年月日,嘿嘿。seq_file的處理方式開(kāi)看有點(diǎn)發(fā)展,步驟有些多,但是安全,是規(guī)范的處理方式。

步驟一:建立proc文件。

  通過(guò)一個(gè)struct proc_dir_entry的元素,在/proc中建立文件,如下:

struct proc_dir_entry * entry = create_proc_entry(“scullseq”,0,NULL)。參數(shù)的內(nèi)容和read_proc,第一個(gè)參數(shù)表示文件名,第二個(gè)參數(shù)表示文件屬性,對(duì)于只讀方式為0,第三個(gè)參數(shù)表示文件路徑,NULL表示缺省路徑,即/proc。

步驟二:關(guān)聯(lián)proc的操作。

   需要對(duì)文件進(jìn)行操作,見(jiàn)過(guò)文件和struct file_operations相關(guān)聯(lián),我們注意到這個(gè)數(shù)據(jù)結(jié)構(gòu)也用于模塊操作關(guān)聯(lián)中。具體操作如下:

#ifdef SCULL_SEQ_FILE 
/* 步驟二:2、定義proc文件所關(guān)聯(lián)的文件操作數(shù)據(jù) */ 
static struct file_operations scull_proc_ops = {  
        .owner  = THIS_MODULE,   
        .open    = scull_proc_open,  //open通常這是我們唯一需要重新定義的函數(shù),需要和特定的seq_file關(guān)聯(lián)起來(lái)。 
        .read     = seq_read,               //采用系統(tǒng)的處理方式 
        .llseek   = seq_lseek,              //采用系統(tǒng)的處理方式 
        .release = seq_release,         //采用系統(tǒng)的處理方式 
};

/* 步驟二:4、在前面的步驟二1~3中我們創(chuàng)建了proc文件,關(guān)聯(lián)了proc文件和file_operations,并進(jìn)一步關(guān)聯(lián)了seq_file,這里我們具體定義被關(guān)聯(lián)的seq_file */ 
static struct seq_operations scull_seq_ops = { 
        .start          = scull_seq_start, 
        .next          = scull_seq_next, 
        .stop          = scull_seq_stop, 
        .show         = scull_seq_show, 
};

static struct proc_dir_entry * entry; 
#endif 
… … 
static int __init scull_init(void) 

… … 
#ifdef SCULL_SEQ_FILE 
        /* 步驟一:創(chuàng)建proc文件*/ 
        entry = create_proc_entry ("scullseq", 0 ,NULL); 
        /* 步驟二:1、將proc文件和對(duì)應(yīng)的文件操作關(guān)聯(lián)起來(lái)*/ 
        if(entry) 
                entry -> proc_fops = & scull_proc_ops ; 
#endif 

... ...  

static void __exit scull_exit(void) 

#ifdef SCULL_SEQ_FILE
 
/* 我們?cè)谀K中創(chuàng)建的proc文件,都應(yīng)該模塊cleanup模塊的時(shí)候刪除,以防影響系統(tǒng),另外,我們應(yīng)該在刪除模塊函數(shù)的開(kāi)始執(zhí)行這個(gè)操作,防止相關(guān)聯(lián)的數(shù)據(jù)已經(jīng)刪除或者注銷后再來(lái)處理,避免異常出現(xiàn)。 */ 
        remove_proc_entry("scullseq",NULL ); 
#endif 
        if(is_get_dev < 0){ 
                return ; 
        }else{ 
                int i = 0; 
                for(i = 0; i < SCULL_DEV_NUM; i ++){ 
                        scull_trim(&mydev[i]); 
                        cdev_del( & mydev[i].cdev ); 
                } 
                unregister_chrdev_region(dev,SCULL_DEV_NUM); 
                WDEBUG(WEI_KERN_NOTICE,"Scull module exit\n"); 
        } 
}

/* 步驟二:3、具體實(shí)現(xiàn)proc文件的open操作,目的與seq_file相關(guān)聯(lián)。*/ 
int scull_proc_open(struct inode * inode , struct file * file) 

        return seq_open(file, & scull_seq_ops ); 
}

步驟三:處理seq_file操作過(guò)程。

  seq_file操作定義了四個(gè)操作,格式如下:

void * start(struct seq_file * s, loff_t * v); 
void * next (struct seq_file * s, void * v, loff_t * pos); 
void   stop (struct seq_file * s, void * v); 
int    show (struct seq_file * s, void * v);

  其中l(wèi)off_t表示位置,這是由我們自己程序控制的,初始為0,在scull中我們依次讀取scull0-3,因此使用該偏移量來(lái)表示我們所讀取的設(shè)備的序號(hào)。

  我們利用void * v來(lái)記錄設(shè)備的入口位置。start根據(jù)編譯量,即我們的設(shè)備的序號(hào),返回scullx的入口位置,無(wú)論下一操作是next,stop,還是show,這個(gè)返回值會(huì)作為參數(shù)void *v輸入。next表示下一查詢,和start相似,只是多了void * v的輸入,同樣它的返回值也作為下一操作的參數(shù)void *v輸入。show用于通過(guò)/proc文件輸出。stop表示一次讀取的結(jié)束。雖然在seq_file中和read_proc不一樣,不需要考慮每次可以輸出的buff的大小,但是實(shí)際讀取不會(huì)連續(xù)一片很大的數(shù)據(jù)輸出,在例子后面,我們將討論這些操作的執(zhí)行。

  輸出方式非常簡(jiǎn)單,一般可以使用seq_printf,另外還有seq_putc,seq_puts,seq_escape。例子如下:

#ifdef SCULL_SEQ_FILE 
void * scull_seq_start (struct seq_file * s, loff_t * pos) 

        printk("==scull_seq_start() enter %p %p %lli\n", s , pos , * pos); 
        if( * pos >= SCULL_DEV_NUM) 
                return NULL; 
        else 
                return mydev + * pos; 
}

void * scull_seq_next (struct seq_file * s, void * v, loff_t * pos) 

        printk("==scull_seq_next() enter %p %p %p %lli\n", s , v, pos , * pos); 
        (* pos ) ++; 
        return scull_seq_start(s, pos); 
}

void scull_seq_stop (struct seq_file * s, void * v) 

       printk("==scull_seq_stop() enter\n"); 
        return ; 
}

int scull_seq_show (struct seq_file * s, void * v) 

        struct scull_dev * dev = (struct scull_dev *) v; 
        struct scull_qset * qs = NULL; 
        int j = 0; 
       printk("==scull_seq_show() enter\n");

        if(down_interruptible(&dev->sem)) 
                return -ERESTARTSYS; 

        seq_printf (s, "\n Device Scull%d: qset %i, q %i sz %li\n", (int) (dev - mydev),dev->qset, dev->quantum, dev->size); 
        printk("\n Device Scull%d: qset %i, q %i sz %li\n", (int) (dev - mydev),dev->qset, dev->quantum, dev->size);

        for(qs = dev->data ; qs ; qs=qs->next){ 
                seq_printf ( s,"  item at %p, qset at %p\n", qs,  qs->data); 
                printk("  item at %p, qset at %p\n", qs,  qs->data); 
                if(qs->data ){ 
                        for(; j < dev->qset /* && qs->data[ j ] */ ;j++){ 
                               seq_printf (s ,"\t%4i:%8p\n",  j,qs->data[ j ]); 
                                printk("\t%4i:%8p\n",  j,qs->data[ j ]); 
                        } 
                } 
        } 

        up(&dev->sem); 
        return 0; 
}

  我們描述一下處理的過(guò)程:當(dāng)我們讀取proc文件,例如cat /proc/scullseq時(shí),我們假設(shè)scull0和scull1都有較多信息輸入。

  一開(kāi)始調(diào)用start,偏移量為0,返回scull0的入口,接著調(diào)用show,scull0的入口作為參數(shù)輸入,在show中,我們可以遍歷scull0的數(shù)據(jù)結(jié)構(gòu),通過(guò)seq_printf輸出。完成show后,由于輸出信息多,進(jìn)入stop,在例子中stop沒(méi)有實(shí)際操作,我們只是用來(lái)跟蹤處理的流程。

   再次調(diào)用start,偏移量步進(jìn)1,即1,返回scull0的入口,接著調(diào)用show,scull1的入口作為參數(shù)輸入,在show中,我們可以遍歷scull1的數(shù)據(jù)結(jié)構(gòu),通過(guò)seq_printf輸出。完成show后,由于輸出信息多,進(jìn)入stop。

  再次調(diào)用start,偏移量步進(jìn)1,即2,返回scull2的入口,接著調(diào)用show,scull2的入口作為參數(shù)輸入,在show中,我們可以遍歷scull2的數(shù)據(jù)結(jié)構(gòu),通過(guò)seq_printf輸出。完成show后,由于輸出信息非常少,kernel認(rèn)為可以繼續(xù)進(jìn)行操作,而不需要stop,調(diào)用next(),在next參數(shù)中輸入的參數(shù)loff_t為2,next將其加一,為3,返回scull3的入口。接著調(diào)用show,scull3的入口作為參數(shù)輸入,在show中,我們可以遍歷scull3的數(shù)據(jù)結(jié)構(gòu),通過(guò)seq_printf輸出。完成show后,由于輸出信息非常少,kernel認(rèn)為可以繼續(xù)進(jìn)行操作,而不需要stop,調(diào)用next()。由于已經(jīng)全部信息返回,在next中發(fā)現(xiàn)沒(méi)有數(shù)據(jù),返回NULL。系統(tǒng)再次調(diào)用start,返回NULL,系統(tǒng)調(diào)用stop,結(jié)束這次輸出。

  再次調(diào)用start,返回NULL,表示已經(jīng)沒(méi)有數(shù)據(jù)輸出,調(diào)用stop,結(jié)束所有的輸出。

  值得注意 seq_file 代碼在調(diào)用 start 和 stop 之間不睡眠或者進(jìn)行其他非原子性任務(wù). 你也肯定會(huì)看到在調(diào)用 start 后馬上有一個(gè) stop 調(diào)用. 因此, 對(duì)你的 start 方法來(lái)說(shuō)請(qǐng)求信號(hào)量或自旋鎖是安全的. 只要你的其他 seq_file 方法是原子的, 調(diào)用的整個(gè)序列是原子的.(http://www.deansys.com/doc/ldd3/ch04s03.html)

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux設(shè)備驅(qū)動(dòng)程序?qū)W習(xí)(1)-字符設(shè)備驅(qū)動(dòng)程序 - Linux設(shè)備驅(qū)動(dòng)程序 - Tek...
字符設(shè)備驅(qū)動(dòng)程序 (1) - LDD3學(xué)習(xí)整理 - 小獸的窩
簡(jiǎn)化的字符設(shè)備驅(qū)動(dòng)程序scull
scull
字符設(shè)備驅(qū)動(dòng)程序及數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介
Linux RTC驅(qū)動(dòng)分析(三)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服