linux seek原理,Linux内核:seek机制
在我們編寫CC1100驅動程序和倒車雷達驅動程序的時候,我們都用到了當前讀取數據標志位,即我們在驅動程序中會定義一個容器用來存放數據,每一次我們讀完一個數據時,我們都會將我們的讀數據變量加1,這樣下一次再來讀取數據的時候就不會讀到以前的數據了,都會是全新的數據。當然這個方法是我們自己在編寫驅動程序時候自己定義的。是否在Linux內核中本來就有這樣的機制呢?答案是肯定的。這個機制就是seek機制,那么seek機制又是如何實現記錄讀取數據位置的機智的呢?同poll機制一樣,在file->fop里面也定義有seek的函數指針,那就是llseek,這個函數指針當然是指向我們自己編寫的驅動程序的函數了。其實seek實現的機制比較簡單,主要就是圍繞當前文件指針file->f_ops這個指針來的,這個指針存放的是當前驅動程序文件的讀寫數據位置,我們在哪里用到了f_ops這個指針呢?首先我們來看一下我們比較熟悉的read函數和open函數,我們知道在這兩個函數中我們所要用到的參數都是一樣的CC1100_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)和static ssize_t CC1100_write(struct file *filp, const char *buff, size_t count, loff_t *offp)其里面的參數都是一樣的,第一個參數是file(該設備文件)、第二個參數是用戶層傳過來的buff指針,第三個是用戶層傳過來的寫入或者讀取長度大小(size_t),那么第四個參數是什么呢,好像我們之前都沒有用過,這第四個參數保存的數據就是我們上面講的file->f_ops,用來記錄我們驅動程序文件的讀取數據的位置。通常如果我們不用seek機制的話,這個參數也一般都用不到,其值永遠都是0。所以從上面我們也可以推出,要想使用read或者是write的第四個參數的話,我們必須使用 seek函數來改變f_ops指針的指向seek的機制就是用來改變文件指針的值的。通常我們使用seek機制都會遵循一定的模板,首先我們要在驅動程序中編寫我們自己的seek函數,大致模板為:
在驅動程序中首先要定義自己的seek函數,通常該函數的模式都是一樣的:
loff_t scull_llseek(struct file *filp, loff_t off, int whence)
{
struct scull_dev *dev = filp->private_data;
loff_t newpos;
switch(whence)
{
case 0: /* SEEK_SET */ //從起始位置進行偏移
newpos = off;
break;
case 1: /* SEEK_CUR */ //從當前位置進行偏移。
newpos = filp->f_pos + off;
break;
case 2: /* SEEK_END */ //以數據容器尾部作為偏移
newpos = dev->size + off;
break;
default: /* can't happen */
return -EINVAL;
}
if (newpos < 0)
return -EINVAL;
filp->f_pos = newpos; //這句代碼就是關鍵,改變驅動文件的f_pos的指向。
return newpos; //返回當前指針
}
同時也必須在file_operations里面指定file_operations->llseek指針的指向scull_llseek函數,方式類似open等函數。
static struct file_operations _fops =
{
.............
.llseek = scull_llseek
..............
}
編寫能夠與llseek配套的write函數,因為seek機制必須要和read、write等函數配套使用才能發揮其效力。
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/
/*分析和獲取有效的寫長度*/
if (p >= GLOBALMEM_SIZE)
return count ? - ENXIO: 0;
if (count > GLOBALMEM_SIZE - p) //當count+p> GLOBALMEM_SIZE則表示如果按照當前的讀取數據大小//和文件指針值讀取數據的話,將會超過數據的最大值
count = GLOBALMEM_SIZE - p;
if (down_interruptible(&dev->sem))//獲得信號量
{
return - ERESTARTSYS;
}
/*用戶空間->內核空間*/
//數據復制的位置將從dev->mem + p開始
if (copy_from_user(dev->mem + p, buf, count))
ret = - EFAULT;
else
{
*ppos +=count;
ret = count;
printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
}
up(&dev->sem); //釋放信號量
return ret;
}
編寫能夠與llseek配套的read函數
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/
/*分析和獲取有效的寫長度*/
if (p >= GLOBALMEM_SIZE)
return count ? - ENXIO: 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
if (down_interruptible(&dev->sem))
{
return - ERESTARTSYS;
}
/*內核空間->用戶空間*/
if (copy_to_user(buf, (void*)(dev->mem + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
}
up(&dev->sem); //釋放信號量
return ret;
}
總結
以上是生活随笔為你收集整理的linux seek原理,Linux内核:seek机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux命令一键卸载nginx,lin
- 下一篇: ubuntu: /lib/modules