2013-01-17 41 views
9

पर एक लेख है: http://lwn.net/Articles/378262/ जो लिनक्स कर्नेल सर्कुलर बफर कार्यान्वयन का वर्णन करता है। के बाद से इस कोड को स्पष्ट रूप से स्मृति आदेश और atomicity spin_lock की बात है क्या के साथ संबंधितलिनक्स कर्नेल परिपत्र बफर को समझना

  1. ():

    यहाँ "निर्माता" है::

    spin_lock(&producer_lock); 
    
    unsigned long head = buffer->head; 
    unsigned long tail = ACCESS_ONCE(buffer->tail); 
    
    if (CIRC_SPACE(head, tail, buffer->size) >= 1) { 
        /* insert one item into the buffer */ 
        struct item *item = buffer[head]; 
    
        produce_item(item); 
    
        smp_wmb(); /* commit the item before incrementing the head */ 
    
        buffer->head = (head + 1) & (buffer->size - 1); 
    
        /* wake_up() will make sure that the head is committed before 
        * waking anyone up */ 
        wake_up(consumer); 
    } 
    
    spin_unlock(&producer_lock); 
    

    प्रश्न मैं कुछ सवाल हैं ?

  2. अभी तक, मेरी समझ यह है कि ACCESS_ONCE संकलक रीडरिंग को रोकता है, सच?
  3. क्या उत्पादन_item (आइटम) आइटम से जुड़े सभी लेखों को बस जारी करता है?
  4. मुझे विश्वास है कि smp_wmb() गारंटी देता है कि product_item (आइटम) में सभी लिखने से पहले "प्रकाशन" लिखने से पहले पूरा हो जाता है। सच?
  5. पृष्ठ पर टिप्पणी जहां मुझे यह कोड मिला है, यह इंगित करता है कि एक smp_wmb() सामान्य रूप से हेड इंडेक्स को अपडेट करने के बाद आवश्यक हो, लेकिन wake_up (उपभोक्ता) ऐसा करता है, इसलिए यह आवश्यक नहीं है। क्या यह सच है? यदि ऐसा है तो क्यों?

    spin_lock(&consumer_lock); 
    
    unsigned long head = ACCESS_ONCE(buffer->head); 
    unsigned long tail = buffer->tail; 
    
    if (CIRC_CNT(head, tail, buffer->size) >= 1) { 
        /* read index before reading contents at that index */ 
        smp_read_barrier_depends(); 
    
        /* extract one item from the buffer */ 
        struct item *item = buffer[tail]; 
    
        consume_item(item); 
    
        smp_mb(); /* finish reading descriptor before incrementing tail */ 
    
        buffer->tail = (tail + 1) & (buffer->size - 1); 
    } 
    
    spin_unlock(&consumer_lock); 
    

    प्रश्न "उपभोक्ता" के लिए विशिष्ट:

यहाँ "उपभोक्ता" है

  1. क्या smp_read_barrier_depends() क्या करता है? एक मंच में कुछ टिप्पणियों से ऐसा लगता है कि आप यहां एक smp_rmb() जारी कर सकते थे, लेकिन कुछ आर्किटेक्चर पर यह अनावश्यक (x86) और बहुत महंगा है, इसलिए smp_read_barrier_depends() को वैकल्पिक रूप से ऐसा करने के लिए बनाया गया था ... उसने कहा, वास्तव में समझ में नहीं आता क्यों smp_rmb() हमेशा जरूरी है!
  2. क्या smp_mb() वहाँ यह गारंटी देने के लिए है कि इसके बाद लिखने से पहले सभी पढ़े जाएंगे?

उत्तर

7

निर्माता के लिए:

  1. यहाँ spin_lock() एक ही समय में कतार संशोधित करने के लिए कोशिश कर रहा से दो उत्पादकों को रोकने के लिए है।
  2. ACCESS_ONCE रीडरिंग को रोकता है, यह संकलक को बाद में मूल्य को पुनः लोड करने से रोकता है। (an article about ACCESS_ONCE on LWN है जो इस पर विस्तार करता है)
  3. सही।
  4. भी सही है।
  5. उपभोक्ता को जागने से पहले यहां (अंतर्निहित) लिखने की बाधा की आवश्यकता है अन्यथा उपभोक्ता अद्यतन head मान नहीं देख सकता है।

उपभोक्ता:

  1. smp_read_barrier_depends() (2 देखें) एक डेटा निर्भरता बाधा है, जो एक पढ़ने बाधा का एक कमजोर रूप है। इस मामले में प्रभाव यह सुनिश्चित करना है कि buffer->tail इसे buffer[tail] में सरणी अनुक्रमणिका के रूप में उपयोग करने से पहले पढ़ा जाए।
  2. smp_mb() यहां एक पूर्ण स्मृति बाधा है, यह सुनिश्चित करना कि सभी पढ़ और लिख इस बिंदु से किए गए हैं।

अतिरिक्त संदर्भ:

(नोट: मैं पूरी तरह से निर्माता में 5 और 1 उपभोक्ता के लिए के लिए अपने जवाब के बारे में निश्चित नहीं हूँ, लेकिन मेरा मानना ​​है कि वे ' तथ्यों का एक उचित अनुमान है। मैं मेमोरी बाधाओं के बारे में प्रलेखन पृष्ठ को पढ़ने की अत्यधिक अनुशंसा करता हूं, क्योंकि यह यहां लिखने वाले किसी भी चीज़ से अधिक व्यापक है।)