linux核心————隊列
linux核心——隊列
定義:
struct __kfifo{unsigned int in; //入隊位移,寫索引unsigned int out; //出隊位移,讀索引unsigned int mask;unsigned int esize;void *data;}
使用:
建立一個隊列,該函數建立並初始化一個大小為size的kfifo:
38 int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, 39 size_t esize, gfp_t gfp_mask) 40 { 45 size = roundup_pow_of_two(size); 46 47 fifo->in = 0; 48 fifo->out = 0; 49 fifo->esize = esize; 50 51 if (size < 2) { 52 fifo->data = NULL; 53 fifo->mask = 0; 54 return -EINVAL; 55 } 56 57 fifo->data = kmalloc(size * esize, gfp_mask); 58 59 if (!fifo->data) { 60 fifo->mask = 0; 61 return -ENOMEM; 62 } 63 fifo->mask = size - 1; 64 65 return 0; 66 }
判斷一個整數是否是2的整數次冪
static inline int is_power_of_2(unsigned long long n) {return (n!=0 &&(n&(n-1)==0)) }
推入資料到隊列的方法是kfifo_in()函數
102 static void kfifo_copy_in(struct __kfifo *fifo, const void *src,103 unsigned int len, unsigned int off)104 {105 unsigned int size = fifo->mask + 1;106 unsigned int esize = fifo->esize;107 unsigned int l;108 109 off &= fifo->mask; //該操作從數學角度將就是對長度fifo->mask的模數運算 110 if (esize != 1) {111 off *= esize;112 size *= esize;113 len *= esize;114 }115 l = min(len, size - off); //size-off代表的含義是當前in到緩衝區尾的大小,116 /*先從buffer中拷貝l位元組到緩衝區剩餘空間,l<=len,也<=從real_in開始到緩衝區結尾的空間 所以這個copy可能沒拷貝完,但是不會造成緩衝區越界 */117 memcpy(fifo->data + off, src, l); /*len > l時,拷貝buffer中剩餘的內容,其真實位址當然為buffer + l,而剩餘的大小為len - l 當len == l時,下面的memcpy啥都不幹*/118 memcpy(fifo->data, src + l, len - l);123 smp_wmb();124 }125 126 unsigned int __kfifo_in(struct __kfifo *fifo,127 const void *buf, unsigned int len) //buf指向的是請求入隊的緩衝區,len表示的是請求寫入的大小128 {129 unsigned int l;131 l = kfifo_unused(fifo);//計算隊列中剩餘空間的大小,fifo->size-(fifo->in-fifo->out)132 if (len > l)133 len = l;135 kfifo_copy_in(fifo, buf, len, fifo->in);136 fifo->in += len;137 return len;138 }
kfifo的巧妙之處在於in和out定義為無符號類型,在put和get時,in和out都是增加,當達到最大值時,產生溢出,使得從0開始,進行迴圈使用