轉 Linux kernel 無鎖隊列

來源:互聯網
上載者:User

標籤:blog   http   使用   strong   資料   art   

  1. struct kfifo {   
  2.     unsigned char *buffer;    /* the buffer holding the data */   
  3.     unsigned int size;    /* the size of the allocated buffer */   
  4.     unsigned int in;    /* data is added at offset (in % size) */   
  5.     unsigned int out;    /* data is extracted from off. (out % size) */   
  6.     spinlock_t *lock;    /* protects concurrent modifications */   
  7. };

 

  1. struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)   
  2. {   
  3.     unsigned char *buffer;   
  4.     struct kfifo *ret;   
  5.   
  6.     /*  
  7.      * round up to the next power of 2, since our ‘let the indices  
  8.      * wrap‘ tachnique works only in this case.  
  9.      */   
  10.     if (size & (size - 1)) {   
  11.         BUG_ON(size > 0x80000000);   
  12.         size = roundup_pow_of_two(size);   
  13.     }   
  14.   
  15.     buffer = kmalloc(size, gfp_mask);   
  16.     if (!buffer)   
  17.         return ERR_PTR(-ENOMEM);   
  18.   
  19.     ret = kfifo_init(buffer, size, gfp_mask, lock);   
  20.   
  21.     if (IS_ERR(ret))   
  22.         kfree(buffer);   
  23.   
  24.     return ret;   
  25. }   

 

這裡值得一提的是,kfifo->size的值總是在調用者傳進來的size參數的基礎上向2的冪擴充,這是核心一貫的做法。這樣的好處不言而喻--對kfifo->size模數運算可以轉化為與運算,如下:

kfifo->in % kfifo->size 可以轉化為 kfifo->in & (kfifo->size – 1)

在kfifo_alloc函數中,使用size & (size – 1)來判斷size 是否為2冪,如果條件為真,則表示size不是2的冪,然後調用roundup_pow_of_two將之向上擴充為2的冪。 這些都是很常用的技巧,只不過大家沒有將它們結合起來使用而已,下面要分析的__kfifo_put和__kfifo_get則是將kfifo->size的特點發揮到了極致。

 

3. __kfifo_put和__kfifo_get,巧妙的入隊和出隊操作,無鎖並發

__kfifo_put是入隊操作,它先將資料放入buffer裡面,最後才修改in參數;__kfifo_get是出隊操作,它先將資料從buffer中移走,最後才修改out。你會發現in和out兩者各司其職。電腦科學家已經證明,當只有一個讀經程和一個寫線程並行作業時,不需要任何額外的鎖,就可以確保是安全執行緒的,也即kfifo使用了無鎖編程技術,以提高kernel的並發。

下面是__kfifo_put和__kfifo_get的代碼

 

 

[cpp] view plaincopyprint? 
  1. unsigned int __kfifo_put(struct kfifo *fifo,   
  2.              unsigned char *buffer, unsigned int len)   
  3. {   
  4.     unsigned int l;   
  5.   
  6.     len = min(len, fifo->size - fifo->in + fifo->out);   
  7.   
  8.     /*  
  9.      * Ensure that we sample the fifo->out index -before- we  
  10.      * start putting bytes into the kfifo.  
  11.      */   
  12.   
  13.     smp_mb();   
  14.   
  15.     /* first put the data starting from fifo->in to buffer end */   
  16.     l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));   
  17.     memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);   
  18.   
  19.     /* then put the rest (if any) at the beginning of the buffer */   
  20.     memcpy(fifo->buffer, buffer + l, len - l);   
  21.   
  22.     /*  
  23.      * Ensure that we add the bytes to the kfifo -before-  
  24.      * we update the fifo->in index.  
  25.      */   
  26.   
  27.     smp_wmb();   
  28.   
  29.     fifo->in += len;   
  30.   
  31.     return len;   
  32. }  
  33.   
  34. unsigned int __kfifo_get(struct kfifo *fifo,   
  35.              unsigned char *buffer, unsigned int len)   
  36. {   
  37.     unsigned int l;   
  38.   
  39.     len = min(len, fifo->in - fifo->out);   
  40.   
  41.     /*  
  42.      * Ensure that we sample the fifo->in index -before- we  
  43.      * start removing bytes from the kfifo.  
  44.      */   
  45.   
  46.     smp_rmb();   
  47.   
  48.     /* first get the data from fifo->out until the end of the buffer */   
  49.     l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));   
  50.     memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);   
  51.   
  52.     /* then get the rest (if any) from the beginning of the buffer */   
  53.     memcpy(buffer + l, fifo->buffer, len - l);   
  54.   
  55.     /*  
  56.      * Ensure that we remove the bytes from the kfifo -before-  
  57.      * we update the fifo->out index.  
  58.      */   
  59.   
  60.     smp_mb();   
  61.   
  62.     fifo->out += len;   
  63.   
  64.     return len;   
  65. }   

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.