Osphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget-/translations/zh_CN/core-api/circular-buffersmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget-/translations/zh_TW/core-api/circular-buffersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget-/translations/it_IT/core-api/circular-buffersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget-/translations/ja_JP/core-api/circular-buffersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget-/translations/ko_KR/core-api/circular-buffersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget-/translations/sp_SP/core-api/circular-buffersmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhsection)}(hhh](htitle)}(hCircular Buffersh]hCircular Buffers}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhG/var/lib/git/docbuild/linux/Documentation/core-api/circular-buffers.rsthKubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hAuthorh]hAuthor}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(h#David Howells h]h paragraph)}(hhh](hDavid Howells <}(hhhhhNhNubh reference)}(hdhowells@redhat.comh]hdhowells@redhat.com}(hhhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:dhowells@redhat.comuh1hhhubh>}(hhhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hAuthorh]hAuthor}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(h*Paul E. McKenney h]h)}(h(Paul E. McKenney h](hPaul E. McKenney <}(hjhhhNhNubh)}(hpaulmck@linux.ibm.comh]hpaulmck@linux.ibm.com}(hj%hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:paulmck@linux.ibm.comuh1hhjubh>}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(h{Linux provides a number of features that can be used to implement circular buffering. There are two sets of such features:h]h{Linux provides a number of features that can be used to implement circular buffering. There are two sets of such features:}(hjQhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK hhhhubh block_quote)}(h(1) Convenience functions for determining information about power-of-2 sized buffers. (2) Memory barriers for when the producer and the consumer of objects in the buffer don't want to share a lock. h]henumerated_list)}(hhh](h list_item)}(hRConvenience functions for determining information about power-of-2 sized buffers. h]h)}(hQConvenience functions for determining information about power-of-2 sized buffers.h]hQConvenience functions for determining information about power-of-2 sized buffers.}(hjphhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK hjlubah}(h]h ]h"]h$]h&]uh1jjhjgubjk)}(hlMemory barriers for when the producer and the consumer of objects in the buffer don't want to share a lock. h]h)}(hkMemory barriers for when the producer and the consumer of objects in the buffer don't want to share a lock.h]hmMemory barriers for when the producer and the consumer of objects in the buffer don’t want to share a lock.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jjhjgubeh}(h]h ]h"]h$]h&]enumtypearabicprefix(suffix)uh1jehjaubah}(h]h ]h"]h$]h&]uh1j_hhhK hhhhubh)}(hTo use these facilities, as discussed below, there needs to be just one producer and just one consumer. It is possible to handle multiple producers by serialising them, and to handle multiple consumers by serialising them.h]hTo use these facilities, as discussed below, there needs to be just one producer and just one consumer. It is possible to handle multiple producers by serialising them, and to handle multiple consumers by serialising them.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubhcomment)}(hContents: (*) What is a circular buffer? (*) Measuring power-of-2 buffers. (*) Using memory barriers with circular buffers. - The producer. - The consumer.h]hContents: (*) What is a circular buffer? (*) Measuring power-of-2 buffers. (*) Using memory barriers with circular buffers. - The producer. - The consumer.}hjsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1jhhhhhhhK"ubh)}(hhh](h)}(hWhat is a circular buffer?h]hWhat is a circular buffer?}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhK$ubh)}(hFirst of all, what is a circular buffer? A circular buffer is a buffer of fixed, finite size into which there are two indices:h]hFirst of all, what is a circular buffer? A circular buffer is a buffer of fixed, finite size into which there are two indices:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK&hjhhubj`)}(h(1) A 'head' index - the point at which the producer inserts items into the buffer. (2) A 'tail' index - the point at which the consumer finds the next item in the buffer. h]jf)}(hhh](jk)}(hPA 'head' index - the point at which the producer inserts items into the buffer. h]h)}(hOA 'head' index - the point at which the producer inserts items into the buffer.h]hSA ‘head’ index - the point at which the producer inserts items into the buffer.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK)hjubah}(h]h ]h"]h$]h&]uh1jjhjubjk)}(hTA 'tail' index - the point at which the consumer finds the next item in the buffer. h]h)}(hSA 'tail' index - the point at which the consumer finds the next item in the buffer.h]hWA ‘tail’ index - the point at which the consumer finds the next item in the buffer.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK,hj ubah}(h]h ]h"]h$]h&]uh1jjhjubeh}(h]h ]h"]h$]h&]jjjjjjuh1jehjubah}(h]h ]h"]h$]h&]uh1j_hhhK)hjhhubh)}(hTypically when the tail pointer is equal to the head pointer, the buffer is empty; and the buffer is full when the head pointer is one less than the tail pointer.h]hTypically when the tail pointer is equal to the head pointer, the buffer is empty; and the buffer is full when the head pointer is one less than the tail pointer.}(hj0hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK/hjhhubh)}(hX$The head index is incremented when items are added, and the tail index when items are removed. The tail index should never jump the head index, and both indices should be wrapped to 0 when they reach the end of the buffer, thus allowing an infinite amount of data to flow through the buffer.h]hX$The head index is incremented when items are added, and the tail index when items are removed. The tail index should never jump the head index, and both indices should be wrapped to 0 when they reach the end of the buffer, thus allowing an infinite amount of data to flow through the buffer.}(hj>hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK3hjhhubh)}(hXTypically, items will all be of the same unit size, but this isn't strictly required to use the techniques below. The indices can be increased by more than 1 if multiple items or variable-sized items are to be included in the buffer, provided that neither index overtakes the other. The implementer must be careful, however, as a region more than one unit in size may wrap the end of the buffer and be broken into two segments.h]hXTypically, items will all be of the same unit size, but this isn’t strictly required to use the techniques below. The indices can be increased by more than 1 if multiple items or variable-sized items are to be included in the buffer, provided that neither index overtakes the other. The implementer must be careful, however, as a region more than one unit in size may wrap the end of the buffer and be broken into two segments.}(hjLhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK8hjhhubeh}(h]what-is-a-circular-bufferah ]h"]what is a circular buffer?ah$]h&]uh1hhhhhhhhK$ubh)}(hhh](h)}(hMeasuring power-of-2 buffersh]hMeasuring power-of-2 buffers}(hjehhhNhNubah}(h]h ]h"]h$]h&]uh1hhjbhhhhhK@ubh)}(hX)Calculation of the occupancy or the remaining capacity of an arbitrarily sized circular buffer would normally be a slow operation, requiring the use of a modulus (divide) instruction. However, if the buffer is of a power-of-2 size, then a much quicker bitwise-AND instruction can be used instead.h]hX)Calculation of the occupancy or the remaining capacity of an arbitrarily sized circular buffer would normally be a slow operation, requiring the use of a modulus (divide) instruction. However, if the buffer is of a power-of-2 size, then a much quicker bitwise-AND instruction can be used instead.}(hjshhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKBhjbhhubh)}(hgLinux provides a set of macros for handling power-of-2 circular buffers. These can be made use of by::h]hfLinux provides a set of macros for handling power-of-2 circular buffers. These can be made use of by:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKGhjbhhubh literal_block)}(h#include h]h#include }hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKJhjbhhubh)}(hThe macros are:h]hThe macros are:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKLhjbhhubj`)}(hX(#) Measure the remaining capacity of a buffer:: CIRC_SPACE(head_index, tail_index, buffer_size); This returns the amount of space left in the buffer[1] into which items can be inserted. (#) Measure the maximum consecutive immediate space in a buffer:: CIRC_SPACE_TO_END(head_index, tail_index, buffer_size); This returns the amount of consecutive space left in the buffer[1] into which items can be immediately inserted without having to wrap back to the beginning of the buffer. (#) Measure the occupancy of a buffer:: CIRC_CNT(head_index, tail_index, buffer_size); This returns the number of items currently occupying a buffer[2]. (#) Measure the non-wrapping occupancy of a buffer:: CIRC_CNT_TO_END(head_index, tail_index, buffer_size); This returns the number of consecutive items[2] that can be extracted from the buffer without having to wrap back to the beginning of the buffer. h]jf)}(hhh](jk)}(hMeasure the remaining capacity of a buffer:: CIRC_SPACE(head_index, tail_index, buffer_size); This returns the amount of space left in the buffer[1] into which items can be inserted. h](h)}(h,Measure the remaining capacity of a buffer::h]h+Measure the remaining capacity of a buffer:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKNhjubj)}(h0CIRC_SPACE(head_index, tail_index, buffer_size);h]h0CIRC_SPACE(head_index, tail_index, buffer_size);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKPhjubh)}(hXThis returns the amount of space left in the buffer[1] into which items can be inserted.h]hXThis returns the amount of space left in the buffer[1] into which items can be inserted.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKRhjubeh}(h]h ]h"]h$]h&]uh1jjhjubjk)}(hX(Measure the maximum consecutive immediate space in a buffer:: CIRC_SPACE_TO_END(head_index, tail_index, buffer_size); This returns the amount of consecutive space left in the buffer[1] into which items can be immediately inserted without having to wrap back to the beginning of the buffer. h](h)}(h=Measure the maximum consecutive immediate space in a buffer::h]hhead; /* The spin_unlock() and next spin_lock() provide needed ordering. */ unsigned long tail = READ_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_store_release(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);h]hX_spin_lock(&producer_lock); unsigned long head = buffer->head; /* The spin_unlock() and next spin_lock() provide needed ordering. */ unsigned long tail = READ_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_store_release(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);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjhhubh)}(hThis will instruct the CPU that the contents of the new item must be written before the head index makes it available to the consumer and then instructs the CPU that the revised head index must be written before the consumer is woken.h]hThis will instruct the CPU that the contents of the new item must be written before the head index makes it available to the consumer and then instructs the CPU that the revised head index must be written before the consumer is woken.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hXPNote that wake_up() does not guarantee any sort of barrier unless something is actually awakened. We therefore cannot rely on it for ordering. However, there is always one element of the array left empty. Therefore, the producer must produce two elements before it could possibly corrupt the element currently being read by the consumer. Therefore, the unlock-lock pair between consecutive invocations of the consumer provides the necessary ordering between the read of the index indicating that the consumer has vacated a given element and the write by the producer to that same element.h]hXPNote that wake_up() does not guarantee any sort of barrier unless something is actually awakened. We therefore cannot rely on it for ordering. However, there is always one element of the array left empty. Therefore, the producer must produce two elements before it could possibly corrupt the element currently being read by the consumer. Therefore, the unlock-lock pair between consecutive invocations of the consumer provides the necessary ordering between the read of the index indicating that the consumer has vacated a given element and the write by the producer to that same element.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h] the-producerah ]h"] the producerah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(h The Consumerh]h The Consumer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(h,The consumer will look something like this::h]h+The consumer will look something like this:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hXspin_lock(&consumer_lock); /* Read index before reading contents at that index. */ unsigned long head = smp_load_acquire(buffer->head); unsigned long tail = buffer->tail; if (CIRC_CNT(head, tail, buffer->size) >= 1) { /* extract one item from the buffer */ struct item *item = buffer[tail]; consume_item(item); /* Finish reading descriptor before incrementing tail. */ smp_store_release(buffer->tail, (tail + 1) & (buffer->size - 1)); } spin_unlock(&consumer_lock);h]hXspin_lock(&consumer_lock); /* Read index before reading contents at that index. */ unsigned long head = smp_load_acquire(buffer->head); unsigned long tail = buffer->tail; if (CIRC_CNT(head, tail, buffer->size) >= 1) { /* extract one item from the buffer */ struct item *item = buffer[tail]; consume_item(item); /* Finish reading descriptor before incrementing tail. */ smp_store_release(buffer->tail, (tail + 1) & (buffer->size - 1)); } spin_unlock(&consumer_lock);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjhhubh)}(hThis will instruct the CPU to make sure the index is up to date before reading the new item, and then it shall make sure the CPU has finished reading the item before it writes the new tail pointer, which will erase the item.h]hThis will instruct the CPU to make sure the index is up to date before reading the new item, and then it shall make sure the CPU has finished reading the item before it writes the new tail pointer, which will erase the item.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hXuNote the use of READ_ONCE() and smp_load_acquire() to read the opposition index. This prevents the compiler from discarding and reloading its cached value. This isn't strictly needed if you can be sure that the opposition index will _only_ be used the once. The smp_load_acquire() additionally forces the CPU to order against subsequent memory references. Similarly, smp_store_release() is used in both algorithms to write the thread's index. This documents the fact that we are writing to something that can be read concurrently, prevents the compiler from tearing the store, and enforces ordering against previous accesses.h]hXyNote the use of READ_ONCE() and smp_load_acquire() to read the opposition index. This prevents the compiler from discarding and reloading its cached value. This isn’t strictly needed if you can be sure that the opposition index will _only_ be used the once. The smp_load_acquire() additionally forces the CPU to order against subsequent memory references. Similarly, smp_store_release() is used in both algorithms to write the thread’s index. This documents the fact that we are writing to something that can be read concurrently, prevents the compiler from tearing the store, and enforces ordering against previous accesses.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h] the-consumerah ]h"] the consumerah$]h&]uh1hhjhhhhhKubeh}(h]+using-memory-barriers-with-circular-buffersah ]h"]+using memory barriers with circular buffersah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hFurther readingh]hFurther reading}(hj:hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj7hhhhhKubh)}(hbSee also Documentation/memory-barriers.txt for a description of Linux's memory barrier facilities.h]hdSee also Documentation/memory-barriers.txt for a description of Linux’s memory barrier facilities.}(hjHhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj7hhubeh}(h]further-readingah ]h"]further readingah$]h&]uh1hhhhhhhhKubeh}(h]circular-buffersah ]h"]circular buffersah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jcj`j_j\jjj4j1jjj,j)j[jXu nametypes}(jcj_jj4jj,j[uh}(j`hj\jjjbj1jjjj)jjXj7u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}Rparse_messages]transform_messages] transformerN include_log] decorationNhhub.