xref: /dpdk/doc/guides/prog_guide/ring_lib.rst (revision b5458e2cc48349b314c7354e4ddfd2100bd55c29)
1..  SPDX-License-Identifier: BSD-3-Clause
2    Copyright(c) 2010-2014 Intel Corporation.
3
4Ring Library
5============
6
7The ring allows the management of queues.
8Instead of having a linked list of infinite size, the rte_ring has the following properties:
9
10*   FIFO
11
12*   Maximum size is fixed, the objects are stored in a table
13
14*   Objects can be pointers or elements of multiple of 4 byte size
15
16*   Lockless implementation
17
18*   Multi-consumer or single-consumer dequeue
19
20*   Multi-producer or single-producer enqueue
21
22*   Bulk dequeue - Dequeues the specified count of objects if successful; otherwise fails
23
24*   Bulk enqueue - Enqueues the specified count of objects if successful; otherwise fails
25
26*   Burst dequeue - Dequeue the maximum available objects if the specified count cannot be fulfilled
27
28*   Burst enqueue - Enqueue the maximum available objects if the specified count cannot be fulfilled
29
30The advantages of this data structure over a linked list queue are as follows:
31
32*   Faster; only requires a single 32 bit Compare-And-Swap instruction instead of several pointer size Compare-And-Swap instructions.
33
34*   Simpler than a full lockless queue.
35
36*   Adapted to bulk enqueue/dequeue operations.
37    As objects are stored in a table, a dequeue of several objects will not produce as many cache misses as in a linked queue.
38    Also, a bulk dequeue of many objects does not cost more than a dequeue of a simple object.
39
40The disadvantages:
41
42*   Size is fixed
43
44*   Having many rings costs more in terms of memory than a linked list queue. An empty ring contains at least N objects.
45
46A simplified representation of a Ring is shown in with consumer and producer head and tail pointers to objects stored in the data structure.
47
48.. _figure_ring1:
49
50.. figure:: img/ring1.*
51
52   Ring Structure
53
54
55References for Ring Implementation in FreeBSD*
56----------------------------------------------
57
58The following code was added in FreeBSD 8.0, and is used in some network device drivers (at least in Intel drivers):
59
60    * `bufring.h in FreeBSD <http://svn.freebsd.org/viewvc/base/release/8.0.0/sys/sys/buf_ring.h?revision=199625&amp;view=markup>`_
61
62    * `bufring.c in FreeBSD <http://svn.freebsd.org/viewvc/base/release/8.0.0/sys/kern/subr_bufring.c?revision=199625&amp;view=markup>`_
63
64Lockless Ring Buffer in Linux*
65------------------------------
66
67The following is a link describing the `Linux Lockless Ring Buffer Design <http://lwn.net/Articles/340400/>`_.
68
69Additional Features
70-------------------
71
72Name
73~~~~
74
75A ring is identified by a unique name.
76It is not possible to create two rings with the same name (rte_ring_create() returns NULL if this is attempted).
77
78Use Cases
79---------
80
81Use cases for the Ring library include:
82
83    *  Communication between applications in the DPDK
84
85    *  Used by memory pool allocator
86
87Anatomy of a Ring Buffer
88------------------------
89
90This section explains how a ring buffer operates.
91The ring structure is composed of two head and tail couples; one is used by producers and one is used by the consumers.
92The figures of the following sections refer to them as prod_head, prod_tail, cons_head and cons_tail.
93
94Each figure represents a simplified state of the ring, which is a circular buffer.
95The content of the function local variables is represented on the top of the figure,
96and the content of ring structure is represented on the bottom of the figure.
97
98Single Producer Enqueue
99~~~~~~~~~~~~~~~~~~~~~~~
100
101This section explains what occurs when a producer adds an object to the ring.
102In this example, only the producer head and tail (prod_head and prod_tail) are modified,
103and there is only one producer.
104
105The initial state is to have a prod_head and prod_tail pointing at the same location.
106
107Enqueue First Step
108^^^^^^^^^^^^^^^^^^
109
110First, *ring->prod_head* and ring->cons_tail are copied in local variables.
111The prod_next local variable points to the next element of the table, or several elements after in case of bulk enqueue.
112
113If there is not enough room in the ring (this is detected by checking cons_tail), it returns an error.
114
115
116.. _figure_ring-enqueue1:
117
118.. figure:: img/ring-enqueue1.*
119
120   Enqueue first step
121
122
123Enqueue Second Step
124^^^^^^^^^^^^^^^^^^^
125
126The second step is to modify *ring->prod_head* in ring structure to point to the same location as prod_next.
127
128The added object is copied in the ring (obj4).
129
130
131.. _figure_ring-enqueue2:
132
133.. figure:: img/ring-enqueue2.*
134
135   Enqueue second step
136
137
138Enqueue Last Step
139^^^^^^^^^^^^^^^^^
140
141Once the object is added in the ring, ring->prod_tail in the ring structure is modified to point to the same location as *ring->prod_head*.
142The enqueue operation is finished.
143
144
145.. _figure_ring-enqueue3:
146
147.. figure:: img/ring-enqueue3.*
148
149   Enqueue last step
150
151
152Single Consumer Dequeue
153~~~~~~~~~~~~~~~~~~~~~~~
154
155This section explains what occurs when a consumer dequeues an object from the ring.
156In this example, only the consumer head and tail (cons_head and cons_tail) are modified and there is only one consumer.
157
158The initial state is to have a cons_head and cons_tail pointing at the same location.
159
160Dequeue First Step
161^^^^^^^^^^^^^^^^^^
162
163First, ring->cons_head and ring->prod_tail are copied in local variables.
164The cons_next local variable points to the next element of the table, or several elements after in the case of bulk dequeue.
165
166If there are not enough objects in the ring (this is detected by checking prod_tail), it returns an error.
167
168
169.. _figure_ring-dequeue1:
170
171.. figure:: img/ring-dequeue1.*
172
173   Dequeue first step
174
175
176Dequeue Second Step
177^^^^^^^^^^^^^^^^^^^
178
179The second step is to modify ring->cons_head in the ring structure to point to the same location as cons_next.
180
181The dequeued object (obj1) is copied in the pointer given by the user.
182
183
184.. _figure_ring-dequeue2:
185
186.. figure:: img/ring-dequeue2.*
187
188   Dequeue second step
189
190
191Dequeue Last Step
192^^^^^^^^^^^^^^^^^
193
194Finally, ring->cons_tail in the ring structure is modified to point to the same location as ring->cons_head.
195The dequeue operation is finished.
196
197
198.. _figure_ring-dequeue3:
199
200.. figure:: img/ring-dequeue3.*
201
202   Dequeue last step
203
204
205Multiple Producers Enqueue
206~~~~~~~~~~~~~~~~~~~~~~~~~~
207
208This section explains what occurs when two producers concurrently add an object to the ring.
209In this example, only the producer head and tail (prod_head and prod_tail) are modified.
210
211The initial state is to have a prod_head and prod_tail pointing at the same location.
212
213Multiple Producers Enqueue First Step
214^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
215
216On both cores, *ring->prod_head* and ring->cons_tail are copied in local variables.
217The prod_next local variable points to the next element of the table,
218or several elements after in the case of bulk enqueue.
219
220If there is not enough room in the ring (this is detected by checking cons_tail), it returns an error.
221
222
223.. _figure_ring-mp-enqueue1:
224
225.. figure:: img/ring-mp-enqueue1.*
226
227   Multiple producer enqueue first step
228
229
230Multiple Producers Enqueue Second Step
231^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
232
233The second step is to modify ring->prod_head in the ring structure to point to the same location as prod_next.
234This operation is done using a Compare And Swap (CAS) instruction, which does the following operations atomically:
235
236*   If ring->prod_head is different to local variable prod_head,
237    the CAS operation fails, and the code restarts at first step.
238
239*   Otherwise, ring->prod_head is set to local prod_next,
240    the CAS operation is successful, and processing continues.
241
242In the figure, the operation succeeded on core 1, and step one restarted on core 2.
243
244
245.. _figure_ring-mp-enqueue2:
246
247.. figure:: img/ring-mp-enqueue2.*
248
249   Multiple producer enqueue second step
250
251
252Multiple Producers Enqueue Third Step
253^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
254
255The CAS operation is retried on core 2 with success.
256
257The core 1 updates one element of the ring(obj4), and the core 2 updates another one (obj5).
258
259
260.. _figure_ring-mp-enqueue3:
261
262.. figure:: img/ring-mp-enqueue3.*
263
264   Multiple producer enqueue third step
265
266
267Multiple Producers Enqueue Fourth Step
268^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
269
270Each core now wants to update ring->prod_tail.
271A core can only update it if ring->prod_tail is equal to the prod_head local variable.
272This is only true on core 1. The operation is finished on core 1.
273
274
275.. _figure_ring-mp-enqueue4:
276
277.. figure:: img/ring-mp-enqueue4.*
278
279   Multiple producer enqueue fourth step
280
281
282Multiple Producers Enqueue Last Step
283^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
284
285Once ring->prod_tail is updated by core 1, core 2 is allowed to update it too.
286The operation is also finished on core 2.
287
288
289.. _figure_ring-mp-enqueue5:
290
291.. figure:: img/ring-mp-enqueue5.*
292
293   Multiple producer enqueue last step
294
295
296Modulo 32-bit Indexes
297~~~~~~~~~~~~~~~~~~~~~
298
299In the preceding figures, the prod_head, prod_tail, cons_head and cons_tail indexes are represented by arrows.
300In the actual implementation, these values are not between 0 and size(ring)-1 as would be assumed.
301The indexes are between 0 and 2^32 -1, and we mask their value when we access the object table (the ring itself).
30232-bit modulo also implies that operations on indexes (such as, add/subtract) will automatically do 2^32 modulo
303if the result overflows the 32-bit number range.
304
305The following are two examples that help to explain how indexes are used in a ring.
306
307.. note::
308
309    To simplify the explanation, operations with modulo 16-bit are used instead of modulo 32-bit.
310    In addition, the four indexes are defined as unsigned 16-bit integers,
311    as opposed to unsigned 32-bit integers in the more realistic case.
312
313
314.. _figure_ring-modulo1:
315
316.. figure:: img/ring-modulo1.*
317
318   Modulo 32-bit indexes - Example 1
319
320
321This ring contains 11000 entries.
322
323
324.. _figure_ring-modulo2:
325
326.. figure:: img/ring-modulo2.*
327
328      Modulo 32-bit indexes - Example 2
329
330
331This ring contains 12536 entries.
332
333.. note::
334
335    For ease of understanding, we use modulo 65536 operations in the above examples.
336    In real execution cases, this is redundant for low efficiency, but is done automatically when the result overflows.
337
338The code always maintains a distance between producer and consumer between 0 and size(ring)-1.
339Thanks to this property, we can do subtractions between 2 index values in a modulo-32bit base:
340that's why the overflow of the indexes is not a problem.
341
342At any time, entries and free_entries are between 0 and size(ring)-1,
343even if only the first term of subtraction has overflowed:
344
345.. code-block:: c
346
347    uint32_t entries = (prod_tail - cons_head);
348    uint32_t free_entries = (mask + cons_tail -prod_head);
349
350Producer/consumer synchronization modes
351---------------------------------------
352
353rte_ring supports different synchronization modes for producers and consumers.
354These modes can be specified at ring creation/init time via ``flags``
355parameter.
356That should help users to configure ring in the most suitable way for his
357specific usage scenarios.
358Currently supported modes:
359
360.. _Ring_Library_MPMC_Mode:
361
362MP/MC (default one)
363~~~~~~~~~~~~~~~~~~~
364
365Multi-producer (/multi-consumer) mode. This is a default enqueue (/dequeue)
366mode for the ring. In this mode multiple threads can enqueue (/dequeue)
367objects to (/from) the ring. For 'classic' DPDK deployments (with one thread
368per core) this is usually the most suitable and fastest synchronization mode.
369As a well known limitation - it can perform quite pure on some overcommitted
370scenarios.
371
372.. _Ring_Library_SPSC_Mode:
373
374SP/SC
375~~~~~
376Single-producer (/single-consumer) mode. In this mode only one thread at a time
377is allowed to enqueue (/dequeue) objects to (/from) the ring.
378
379.. _Ring_Library_MT_RTS_Mode:
380
381MP_RTS/MC_RTS
382~~~~~~~~~~~~~
383
384Multi-producer (/multi-consumer) with Relaxed Tail Sync (RTS) mode.
385The main difference from the original MP/MC algorithm is that
386tail value is increased not by every thread that finished enqueue/dequeue,
387but only by the last one.
388That allows threads to avoid spinning on ring tail value,
389leaving actual tail value change to the last thread at a given instance.
390That technique helps to avoid the Lock-Waiter-Preemption (LWP) problem on tail
391update and improves average enqueue/dequeue times on overcommitted systems.
392To achieve that RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
393one for head update, second for tail update.
394In comparison the original MP/MC algorithm requires one 32-bit CAS
395for head update and waiting/spinning on tail value.
396
397.. _Ring_Library_MT_HTS_Mode:
398
399MP_HTS/MC_HTS
400~~~~~~~~~~~~~
401
402Multi-producer (/multi-consumer) with Head/Tail Sync (HTS) mode.
403In that mode enqueue/dequeue operation is fully serialized:
404at any given moment only one enqueue/dequeue operation can proceed.
405This is achieved by allowing a thread to proceed with changing ``head.value``
406only when ``head.value == tail.value``.
407Both head and tail values are updated atomically (as one 64-bit value).
408To achieve that 64-bit CAS is used by head update routine.
409That technique also avoids the Lock-Waiter-Preemption (LWP) problem on tail
410update and helps to improve ring enqueue/dequeue behavior in overcommitted
411scenarios. Another advantage of fully serialized producer/consumer -
412it provides the ability to implement MT safe peek API for rte_ring.
413
414Ring Peek API
415-------------
416
417For ring with serialized producer/consumer (HTS sync mode) it is possible
418to split public enqueue/dequeue API into two phases:
419
420*   enqueue/dequeue start
421
422*   enqueue/dequeue finish
423
424That allows user to inspect objects in the ring without removing them
425from it (aka MT safe peek) and reserve space for the objects in the ring
426before actual enqueue.
427Note that this API is available only for two sync modes:
428
429*   Single Producer/Single Consumer (SP/SC)
430
431*   Multi-producer/Multi-consumer with Head/Tail Sync (HTS)
432
433It is a user responsibility to create/init ring with appropriate sync modes
434selected. As an example of usage:
435
436.. code-block:: c
437
438    /* read 1 elem from the ring: */
439    uint32_t n = rte_ring_dequeue_bulk_start(ring, &obj, 1, NULL);
440    if (n != 0) {
441        /* examine object */
442        if (object_examine(obj) == KEEP)
443            /* decided to keep it in the ring. */
444            rte_ring_dequeue_finish(ring, 0);
445        else
446            /* decided to remove it from the ring. */
447            rte_ring_dequeue_finish(ring, n);
448    }
449
450Note that between ``_start_`` and ``_finish_`` none other thread can proceed
451with enqueue(/dequeue) operation till ``_finish_`` completes.
452
453Ring Peek Zero Copy API
454-----------------------
455
456Along with the advantages of the peek APIs, zero copy APIs provide the ability
457to copy the data to the ring memory directly without the need for temporary
458storage (for ex: array of mbufs on the stack).
459
460These APIs make it possible to split public enqueue/dequeue API into 3 phases:
461
462* enqueue/dequeue start
463
464* copy data to/from the ring
465
466* enqueue/dequeue finish
467
468Note that this API is available only for two sync modes:
469
470*   Single Producer/Single Consumer (SP/SC)
471
472*   Multi-producer/Multi-consumer with Head/Tail Sync (HTS)
473
474It is a user responsibility to create/init ring with appropriate sync modes.
475Following is an example of usage:
476
477.. code-block:: c
478
479    /* Reserve space on the ring */
480    n = rte_ring_enqueue_zc_burst_start(r, 32, &zcd, NULL);
481    /* Pkt I/O core polls packets from the NIC */
482    if (n != 0) {
483        nb_rx = rte_eth_rx_burst(portid, queueid, zcd->ptr1, zcd->n1);
484        if (nb_rx == zcd->n1 && n != zcd->n1)
485            nb_rx += rte_eth_rx_burst(portid, queueid, zcd->ptr2,
486							n - zcd->n1);
487        /* Provide packets to the packet processing cores */
488        rte_ring_enqueue_zc_finish(r, nb_rx);
489    }
490
491Note that between ``_start_`` and ``_finish_`` no other thread can proceed
492with enqueue(/dequeue) operation till ``_finish_`` completes.
493
494
495Staged Ordered Ring API
496-----------------------
497
498Staged-Ordered-Ring (SORING) API provides a SW abstraction for *ordered* queues
499with multiple processing *stages*.
500It is based on conventional DPDK ``rte_ring`` API,
501re-uses many of its concepts, and even substantial part of its code.
502It can be viewed as an "extension" of ``rte_ring`` functionality.
503
504In particular, main SORING properties:
505
506* circular ring buffer with fixed size objects and related metadata.
507* producer, consumer plus multiple processing stages in between.
508* allows to split objects processing into multiple stages.
509* objects remain in the same ring while moving from one stage to the other,
510  initial order is preserved, no extra copying needed.
511* preserves the ingress order of objects within the queue across multiple stages.
512* each stage (and producer/consumer) can be served by single and/or multiple threads.
513* number of stages, size and number of objects and their metadata in the ring
514  are configurable at ring initialization time.
515
516Data-Path API
517~~~~~~~~~~~~~
518
519SORING data-path API provided four main operations:
520
521* ``enqueue``/``dequeue`` works in the same manner as for conventional ``rte_ring``,
522  all ``rte_ring`` synchronization types are supported.
523
524* ``acquire``/``release`` - for each stage there is an ``acquire`` (start)
525  and ``release`` (finish) operation.
526  After some objects are ``acquired`` - given thread can safely assume that
527  it has exclusive possession of these objects till ``release`` for them is invoked.
528  Note that right now user has to release exactly the same number of objects
529  that was acquired before.
530  After objects are ``released``, given thread loses its possession on them,
531  and they can be either acquired by next stage or dequeued
532  by the consumer (in case of last stage).
533
534A simplified representation of a SORING with two stages is shown below.
535On that picture ``obj5`` and ``obj4`` elements are acquired by stage 0,
536``obj2`` and ``obj3`` are acquired by stage 1,
537while ``obj1`` was already released by stage 1 and is ready to be consumed.
538
539.. _figure_soring1:
540
541.. figure:: img/soring-pic1.*
542
543Along with traditional flavor there are enhanced versions for
544all these data-path operations: ``enqueux``/``dequeux``/``acquirx``/``releasx``.
545All enhanced versions take as extra parameter a pointer to an array of metadata values.
546At initialization user can request within the ``soring`` supplementary
547and optional array of metadata associated with each object in the ``soring``.
548While ``soring`` element size is configurable and user can specify it big enough
549to hold both object and its metadata together,
550for performance reasons it might be plausible to access them as separate arrays.
551Note that users are free to mix and match both versions of data-path API
552in a way they like.
553As an example, possible usage scenario when such separation helps:
554
555.. code-block:: c
556
557   /*
558    * use pointer to mbuf as soring element, while tx_state as a metadata.
559    * In this example we use a soring with just one stage.
560    */
561    union tx_state {
562        /* negative values for error */
563        int32_t rc;
564        /* otherwise contain valid Tx port and queue IDs*/
565        struct {
566            uint16_t port_id;
567            uint16_t queue_id;
568        } tx;
569    };
570    struct rte_soring *soring;
571
572producer/consumer part:
573
574.. code-block:: c
575
576   struct rte_mbuf *pkts[MAX_PKT_BURST];
577   union tx_state txst[MAX_PKT_BURST];
578   ...
579   /* enqueue - writes to soring objects array no need to update metadata */
580   uint32_t num = MAX_PKT_BURST;
581   num = rte_soring_enqueue_burst(soring, pkts, num, NULL);
582   ....
583   /* dequeux - reads both packets and related tx_state */
584   uint32_t num = MAX_PKT_BURST;
585   num = rte_soring_dequeux_burst(soring, pkts, txst, num, NULL);
586
587   /*
588    * Tx packets out, or drop in case of error.
589    * Note that we don't need to dereference the soring objects itself
590    * to make a decision.
591    */
592   uint32_t i, j, k, n;
593   struct rte_mbuf *dr[MAX_PKT_BURST];
594
595   k = 0;
596   for (i = 0; i != num; i++) {
597       /* packet processing reports an error */
598       if (txst[i].rc < 0)
599           dr[k++] = pkts[i];
600       /* valid packet, send it out */
601       else {
602           /* group consecutive packets with the same port and queue IDs */
603           for (j = i + 1; j < num; j++)
604               if (txst[j].rc != txst[i].rc)
605                   break;
606
607           n = rte_eth_tx_burst(txst[i].tx.port_id, txst[i].tx.queue_id,
608                                pkts + i, j - i);
609           if (i + n != j) {
610               /* decide with unsent packets if any */
611           }
612       }
613   }
614   /* drop erroneous packets */
615   if (k != 0)
616       rte_pktmbuf_free_bulk(dr, k);
617
618acquire/release part:
619
620.. code-block:: c
621
622   uint32_t ftoken;
623   struct rte_mbuf *pkts[MAX_PKT_BURST];
624   union tx_state txst[MAX_PKT_BURST];
625   ...
626   /* acquire - grab some packets to process */
627   uint32_t num = MAX_PKT_BURST;
628   num = rte_soring_acquire_burst(soring, pkts, 0, num, &ftoken, NULL);
629
630   /* process packets, fill txst[] for each */
631   do_process_packets(pkts, txst, num);
632
633   /*
634    * release - assuming that do_process_packets() didn't change
635    * contents of pkts[], we need to update soring metadata array only.
636    */
637   rte_soring_releasx(soring, NULL, txst, 0, num, ftoken);
638
639Use Cases
640~~~~~~~~~
641
642Expected use-cases include applications that use pipeline model
643(probably with multiple stages) for packet processing,
644when preserving incoming packet order is important.
645I.E.: IPsec processing, etc.
646
647SORING internals
648~~~~~~~~~~~~~~~~
649
650* In addition to accessible by the user array of objects (and metadata),
651  ``soring`` also contains an internal array of states.
652  Each ``state[]`` corresponds to exactly one object within the soring.
653  That ``state[]`` array is used by ``acquire``/``release``/``dequeue`` operations
654  to store internal information and should not be accessed by the user directly.
655
656* At ``acquire``, soring  moves stage's head
657  (in a same way as ``rte_ring`` ``move_head`` does),
658  plus it saves in ``state[stage.old_head]`` information
659  about how many elements were acquired, acquired head position,
660  and special flag value to indicate that given elements are acquired
661  (``SORING_ST_START``).
662  Note that ``acquire`` returns an opaque ``ftoken`` value
663  that user has to provide for ``release`` function.
664
665* ``release`` extracts old head value from provided by user ``ftoken``
666  and checks that corresponding ``state[]`` entry contains expected values
667  (mostly for sanity purposes).
668  Then it marks this ``state[]`` entry with ``SORING_ST_FINISH`` flag
669  to indicate that given subset of objects was released.
670  After that, it checks does stage's old ``head`` value
671  equals to its current ``tail`` value.
672  If so, then it performs ``finalize`` operation,
673  otherwise ``release`` just returns.
674
675* As ``state[]`` is shared by all threads,
676  some other thread can perform ``finalize`` operation for given stage.
677  That allows ``release`` to avoid excessive waits on the ``tail`` value.
678  Main purpose of ``finalize`` operation is to walk through ``state[]`` array
679  from current stage's ``tail`` position up to its ``head``,
680  check ``state[]`` and move stage ``tail`` through elements
681  that are already released (in ``SORING_ST_FINISH`` state).
682  Along with that, corresponding ``state[]`` entries are reset back to zero.
683  Note that ``finalize`` for given stage can be called from multiple places:
684  from ``release`` for that stage or from ``acquire`` for next stage,
685  or even from consumer's ``dequeue`` - in case given stage is the last one.
686  So ``finalize`` has to be MT-safe and inside it we have to guarantee that
687  at any given moment only one thread can update stage's ``tail``
688  and reset corresponding ``state[]`` entries.
689
690
691References
692----------
693
694    *   `bufring.h in FreeBSD <http://svn.freebsd.org/viewvc/base/release/8.0.0/sys/sys/buf_ring.h?revision=199625&amp;view=markup>`_ (version 8)
695
696    *   `bufring.c in FreeBSD <http://svn.freebsd.org/viewvc/base/release/8.0.0/sys/kern/subr_bufring.c?revision=199625&amp;view=markup>`_ (version 8)
697
698    *   `Linux Lockless Ring Buffer Design <http://lwn.net/Articles/340400/>`_
699