今天在看linux內核時候,發現內核中的循環緩沖區的設計與實現非常的完美。讓后就想自己仿照著也寫一個,用于加深理解。
linux內核中對struct kfifo結構體的各種操作的源代碼存放在:
/kernel/kfifo.c 和 /include/linux/kfifo.h這兩個文件之中。
struct kfifo
{
linux最新內核版本是多少、unsigned char *buffer;
unsigned int size;? // 用于記錄緩存區的大小;
unsigned int in;??? // 用于記錄下一到達緩存區的數據的存放位置;
unsigned int out;?? // 用于記錄下一次從緩存區提取的數據的位置;
spinlock_t?? *lock; // 用于防止并發的對這個緩存區進行讀操作或寫操作;
};
linux內核開發?通過這個struct kfifo結構體來對一個循環緩存區進行各種信息的統計;
先介紹幾個在對這個緩存區進行各種操作時,需要用到的幾個非常簡單的函數,當然這幾個函數是我自己在寫循環緩存隊列時用到的。
1. 測試一個數是否是 2的冪數
int my_is_power_of_2(int n)
{
return ( n!=0? &&? ( n & (n - 1) ) == 0 );
hdfs原理、}
2. 如果一個數不是2的冪數的話,找出大于這個數的最近的2的冪數
int my_power_of_2(int n)
{
unsigned int i = 0;
if(n)
hdfs block?{
while(n != 0)
{
n = n >> 1;
i++;
}
hdfs shell,return (1 << i);
}
}
此函數的用法: 如果 n = 12 ,不是2的冪數,my_power_of_2(n)返回 16;
n = 17 ,也不是2的冪數, my_power_of_2(n)返回 32;
3.這是一個宏定義,用于取兩個數中最小的數;
hdfs 命令、#define min(m, n) (m) < (n) ? (m) : (n)
min(2,3) min()返回的是 2;
min(10, 4) min()返回的是 4;
開始對循環緩存隊列進行各種操作的函數:
1.循環緩存隊列的初始化:
struct kfifo * fifo_init(unsigned char *buffer, gfp_t gfp_mask, unsigned int len,
linux內核編譯。spinlock_t *spinlock)
{
struct kfifo *fifo = NULL;
fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
if( fifo == NULL )
return -ENOMEM;
Linux 內核。fifo->buffer = buffer;
fifo->size = len;
fifo->in = 0;
fifo->out = 0;
fifo->lock = spinlock;
return fifo;
linux腳本循環,}
kfifo_init()函數主要做的工作是:分配了一個struct kfifo結構體,然后對其進行初始賦值;
2.給struct kfifo結構體分配內存,用于存取緩存的數據
struct kfifo * kfifo_alloc(gfp_t gfp_mask, unsigned int len, spinlock_t *spinlock)
{
struct kfifo *ret = NULL;
linux內核最早是由誰開發的。unsigned char *buffer = NULL;
// 用于判斷len是否是 2的冪數,如果是的話直接使用就可以了
//???? 如果不是的話,使用my_power_of_2()將其調整為2的冪數
if(!my_is_power_of_2(len))
len = my_power_of_2(len);
buffer = kmalloc(len, gfp_mask);
請簡述一下HDFS數據讀取和寫入流程。if( buffer == NULL )
return -ENOMEM;
memset(buffer, 0, len);
ret = kfifio_init(buffer, gfp_mask, len, spinlock);
if( IS_ERR(ret) ) // IS_ERR()函數主要用于判斷返回值是否是像-ENOMEM這類的返回值;
kfree(buffer);
hadoopfs命令詳解。return ret;
}
3.釋放循環緩存隊列中的緩存;
void kfifo_free(struct kfifo *fifo)
{
kfree(fifo->buffer);
linux循環執行命令、kfree(fifo);
}
4.給循環緩存隊列中添加數據的操作(未加鎖的版本)
int __kfifo_put(unsigned char *buffer, unsigned int len, struct kfifo *fifo)
{
unsigned int length ;
linux內核源碼詳解?//fifo->size - fifo->in + fifo->out 這個計算出來的結果值是循環緩存隊列中的未用的
//空間字節數;
len = min(len, fifo->size - fifo->in + fifo->out);
// fifo->size - (fifo->in & (fifo->size -1))計算出來的結果是fifo->in到緩存數組
//末尾的空間大小
length = min(len, fifo->size - ( filo->in & (fifo->size - 1) ) );
hdfs的進程有哪些、memcpy(fifo->buffer + (fifo->in & (fifo->size -1)),buffer, length );
memcpy(fifo->buffer, buffer+length, len-length);
fifo->in +=len;
return len;
}
__kfifo_put()函數返回的是寫入循環隊列中的數據的字節數;因為有可能存在,當要寫入的字節數大于循環隊列中的空閑的空間大小。
linux循環讀取文件內容,5.從循環緩存隊列中取走數據的操作(為加鎖版本)
int __kfifo_get(unsigned char *buffer, int len, struct kfifo *fifo)
{
unsigned int length;
// fifo->in - fifo->out 計算出來的是緩存隊列中存放的字節數;
len = min(len, fifo->in - fifo->out);
hadoop讀寫流程。length = min(len, fifo->size - (fifo->out & (fifo->size - 1))) ;
memcpy( buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), length );
memcpy( buffer+length,? fifo->buffer,? len - length);
fifo->out += len;
return len;
}
__kfifo_get()返回的是從循環隊列中提取的數據的字節數;
6.循環緩存隊列的重置(為加鎖):
inline void __kfifo_reset(struct kfifo *fifo)
{
fifo->in = 0;
fifo->out = 0;
}
7. 循環緩存隊列中的數據長度(為加鎖):
inline int? __kfifo_len(struct kfifo *fifo)
{
return fifo->in - fifo->out;
}
以上的這幾個函數涉及到了對循環緩存隊列的讀寫操作,而在系統中如果同時存在多個進程對這個緩存隊列進行讀寫操作的話,會存在數據的紊亂問題。所以這個循環緩存隊列可以看成是一個臨界區資源,每次只能有一個進程對其進行讀寫操作,不允許并發的讀寫操作。
所以就有了以上幾個函數的加鎖版本了:
1. int kfifo_put(unsigned char *buffer, unsigned int len, struct kfifo *fifo)
{
unsigned int flags;
unsigned int ret;
spin_lock_irqsave(fifo->lock, flags);
ret = __kfifo_put(buffer, len, fifo);
spin_unlock_irqstore(fifo->lock, flags);
return ret;
}
2. int kfifo_get(unsigned char *buffer, unsigned int len, struct kfifo *fifo)
{
unsigned int flags ;
unsigned int ret;
spin_lock_irqsave(fifo->lock, flags);
ret = __kfifo_get(buffer, len, fifo);
spin_unlock_irqstore(fifo->lock, flags);
return ret;
}
3.int kfifo_len(struct kfifo *fifo)
{
unsigned? int flags;
unsigned? int ret;
spin_lock_irqsave(fifo->lock, flags);
ret = __kfifo_len(fifo);
spin_unlock_irqstore(fifo->lock, flags);
return ret;
}
4. void kfifo_reset(struct kfifo *fifo)
{
unsigned int flags;
unsigned int ret;
spin_lock_irqsave(fifo->lock, flags);
__kfifo_reset(fifo);
spin_unlock_irqstore(fifo->lock, flags);
}
看完內核對struct kfifo 結構體的各種操作,感覺在內核代中,每個函數只完成一個功能,并且對循環緩存隊列的讀操作、寫操作、重置操作都非常的簡單,代碼的邏輯也是非常的清晰。
以上代碼是我對模仿內核代碼寫的,當然處理的肯定沒有內核代碼那么完美,比如在內核代碼中對循環隊列緩存區的讀寫操作是要加入內存屏障的。
多看、多想內核代碼,對編程水平幫助很大!
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态