Explorar o código

docs/devel/lockcnt: Convert to rST format

Convert docs/devel/lockcnt.txt to rST format.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240816132212.3602106-4-peter.maydell@linaro.org
Peter Maydell hai 10 meses
pai
achega
362dbb4f3f
Modificáronse 3 ficheiros con 47 adicións e 45 borrados
  1. 1 1
      MAINTAINERS
  2. 1 0
      docs/devel/index-api.rst
  3. 45 44
      docs/devel/lockcnt.rst

+ 1 - 1
MAINTAINERS

@@ -3058,7 +3058,7 @@ F: qapi/run-state.json
 Read, Copy, Update (RCU)
 Read, Copy, Update (RCU)
 M: Paolo Bonzini <pbonzini@redhat.com>
 M: Paolo Bonzini <pbonzini@redhat.com>
 S: Maintained
 S: Maintained
-F: docs/devel/lockcnt.txt
+F: docs/devel/lockcnt.rst
 F: docs/devel/rcu.txt
 F: docs/devel/rcu.txt
 F: include/qemu/rcu*.h
 F: include/qemu/rcu*.h
 F: tests/unit/rcutorture.c
 F: tests/unit/rcutorture.c

+ 1 - 0
docs/devel/index-api.rst

@@ -9,6 +9,7 @@ generated from in-code annotations to function prototypes.
 
 
    bitops
    bitops
    loads-stores
    loads-stores
+   lockcnt
    memory
    memory
    modules
    modules
    pci
    pci

+ 45 - 44
docs/devel/lockcnt.txt → docs/devel/lockcnt.rst

@@ -1,9 +1,9 @@
-DOCUMENTATION FOR LOCKED COUNTERS (aka QemuLockCnt)
-===================================================
+Locked Counters (aka ``QemuLockCnt``)
+=====================================
 
 
 QEMU often uses reference counts to track data structures that are being
 QEMU often uses reference counts to track data structures that are being
 accessed and should not be freed.  For example, a loop that invoke
 accessed and should not be freed.  For example, a loop that invoke
-callbacks like this is not safe:
+callbacks like this is not safe::
 
 
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
         if (ioh->revents & G_IO_OUT) {
         if (ioh->revents & G_IO_OUT) {
@@ -11,11 +11,11 @@ callbacks like this is not safe:
         }
         }
     }
     }
 
 
-QLIST_FOREACH_SAFE protects against deletion of the current node (ioh)
-by stashing away its "next" pointer.  However, ioh->fd_write could
+``QLIST_FOREACH_SAFE`` protects against deletion of the current node (``ioh``)
+by stashing away its ``next`` pointer.  However, ``ioh->fd_write`` could
 actually delete the next node from the list.  The simplest way to
 actually delete the next node from the list.  The simplest way to
 avoid this is to mark the node as deleted, and remove it from the
 avoid this is to mark the node as deleted, and remove it from the
-list in the above loop:
+list in the above loop::
 
 
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
         if (ioh->deleted) {
         if (ioh->deleted) {
@@ -29,7 +29,7 @@ list in the above loop:
     }
     }
 
 
 If however this loop must also be reentrant, i.e. it is possible that
 If however this loop must also be reentrant, i.e. it is possible that
-ioh->fd_write invokes the loop again, some kind of counting is needed:
+``ioh->fd_write`` invokes the loop again, some kind of counting is needed::
 
 
     walking_handlers++;
     walking_handlers++;
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
     QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
@@ -46,8 +46,8 @@ ioh->fd_write invokes the loop again, some kind of counting is needed:
     }
     }
     walking_handlers--;
     walking_handlers--;
 
 
-One may think of using the RCU primitives, rcu_read_lock() and
-rcu_read_unlock(); effectively, the RCU nesting count would take
+One may think of using the RCU primitives, ``rcu_read_lock()`` and
+``rcu_read_unlock()``; effectively, the RCU nesting count would take
 the place of the walking_handlers global variable.  Indeed,
 the place of the walking_handlers global variable.  Indeed,
 reference counting and RCU have similar purposes, but their usage in
 reference counting and RCU have similar purposes, but their usage in
 general is complementary:
 general is complementary:
@@ -70,14 +70,14 @@ general is complementary:
   this can improve performance, but also delay reclamation undesirably.
   this can improve performance, but also delay reclamation undesirably.
   With reference counting, reclamation is deterministic.
   With reference counting, reclamation is deterministic.
 
 
-This file documents QemuLockCnt, an abstraction for using reference
+This file documents ``QemuLockCnt``, an abstraction for using reference
 counting in code that has to be both thread-safe and reentrant.
 counting in code that has to be both thread-safe and reentrant.
 
 
 
 
-QemuLockCnt concepts
---------------------
+``QemuLockCnt`` concepts
+------------------------
 
 
-A QemuLockCnt comprises both a counter and a mutex; it has primitives
+A ``QemuLockCnt`` comprises both a counter and a mutex; it has primitives
 to increment and decrement the counter, and to take and release the
 to increment and decrement the counter, and to take and release the
 mutex.  The counter notes how many visits to the data structures are
 mutex.  The counter notes how many visits to the data structures are
 taking place (the visits could be from different threads, or there could
 taking place (the visits could be from different threads, or there could
@@ -95,13 +95,14 @@ not just frees, though there could be cases where this is not necessary.
 
 
 Reads, instead, can be done without taking the mutex, as long as the
 Reads, instead, can be done without taking the mutex, as long as the
 readers and writers use the same macros that are used for RCU, for
 readers and writers use the same macros that are used for RCU, for
-example qatomic_rcu_read, qatomic_rcu_set, QLIST_FOREACH_RCU, etc.  This is
-because the reads are done outside a lock and a set or QLIST_INSERT_HEAD
+example ``qatomic_rcu_read``, ``qatomic_rcu_set``, ``QLIST_FOREACH_RCU``,
+etc.  This is because the reads are done outside a lock and a set
+or ``QLIST_INSERT_HEAD``
 can happen concurrently with the read.  The RCU API ensures that the
 can happen concurrently with the read.  The RCU API ensures that the
 processor and the compiler see all required memory barriers.
 processor and the compiler see all required memory barriers.
 
 
 This could be implemented simply by protecting the counter with the
 This could be implemented simply by protecting the counter with the
-mutex, for example:
+mutex, for example::
 
 
     // (1)
     // (1)
     qemu_mutex_lock(&walking_handlers_mutex);
     qemu_mutex_lock(&walking_handlers_mutex);
@@ -125,33 +126,33 @@ mutex, for example:
 Here, no frees can happen in the code represented by the ellipsis.
 Here, no frees can happen in the code represented by the ellipsis.
 If another thread is executing critical section (2), that part of
 If another thread is executing critical section (2), that part of
 the code cannot be entered, because the thread will not be able
 the code cannot be entered, because the thread will not be able
-to increment the walking_handlers variable.  And of course
+to increment the ``walking_handlers`` variable.  And of course
 during the visit any other thread will see a nonzero value for
 during the visit any other thread will see a nonzero value for
-walking_handlers, as in the single-threaded code.
+``walking_handlers``, as in the single-threaded code.
 
 
 Note that it is possible for multiple concurrent accesses to delay
 Note that it is possible for multiple concurrent accesses to delay
-the cleanup arbitrarily; in other words, for the walking_handlers
+the cleanup arbitrarily; in other words, for the ``walking_handlers``
 counter to never become zero.  For this reason, this technique is
 counter to never become zero.  For this reason, this technique is
 more easily applicable if concurrent access to the structure is rare.
 more easily applicable if concurrent access to the structure is rare.
 
 
 However, critical sections are easy to forget since you have to do
 However, critical sections are easy to forget since you have to do
-them for each modification of the counter.  QemuLockCnt ensures that
+them for each modification of the counter.  ``QemuLockCnt`` ensures that
 all modifications of the counter take the lock appropriately, and it
 all modifications of the counter take the lock appropriately, and it
 can also be more efficient in two ways:
 can also be more efficient in two ways:
 
 
 - it avoids taking the lock for many operations (for example
 - it avoids taking the lock for many operations (for example
   incrementing the counter while it is non-zero);
   incrementing the counter while it is non-zero);
 
 
-- on some platforms, one can implement QemuLockCnt to hold the lock
+- on some platforms, one can implement ``QemuLockCnt`` to hold the lock
   and the mutex in a single word, making the fast path no more expensive
   and the mutex in a single word, making the fast path no more expensive
   than simply managing a counter using atomic operations (see
   than simply managing a counter using atomic operations (see
-  docs/devel/atomics.rst).  This can be very helpful if concurrent access to
+  :doc:`atomics`).  This can be very helpful if concurrent access to
   the data structure is expected to be rare.
   the data structure is expected to be rare.
 
 
 
 
 Using the same mutex for frees and writes can still incur some small
 Using the same mutex for frees and writes can still incur some small
 inefficiencies; for example, a visit can never start if the counter is
 inefficiencies; for example, a visit can never start if the counter is
-zero and the mutex is taken---even if the mutex is taken by a write,
+zero and the mutex is taken -- even if the mutex is taken by a write,
 which in principle need not block a visit of the data structure.
 which in principle need not block a visit of the data structure.
 However, these are usually not a problem if any of the following
 However, these are usually not a problem if any of the following
 assumptions are valid:
 assumptions are valid:
@@ -163,27 +164,27 @@ assumptions are valid:
 - writes are frequent, but this kind of write (e.g. appending to a
 - writes are frequent, but this kind of write (e.g. appending to a
   list) has a very small critical section.
   list) has a very small critical section.
 
 
-For example, QEMU uses QemuLockCnt to manage an AioContext's list of
+For example, QEMU uses ``QemuLockCnt`` to manage an ``AioContext``'s list of
 bottom halves and file descriptor handlers.  Modifications to the list
 bottom halves and file descriptor handlers.  Modifications to the list
 of file descriptor handlers are rare.  Creation of a new bottom half is
 of file descriptor handlers are rare.  Creation of a new bottom half is
 frequent and can happen on a fast path; however: 1) it is almost never
 frequent and can happen on a fast path; however: 1) it is almost never
 concurrent with a visit to the list of bottom halves; 2) it only has
 concurrent with a visit to the list of bottom halves; 2) it only has
-three instructions in the critical path, two assignments and a smp_wmb().
+three instructions in the critical path, two assignments and a ``smp_wmb()``.
 
 
 
 
-QemuLockCnt API
----------------
+``QemuLockCnt`` API
+-------------------
 
 
-The QemuLockCnt API is described in include/qemu/thread.h.
+The ``QemuLockCnt`` API is described in ``include/qemu/thread.h``.
 
 
 
 
-QemuLockCnt usage
------------------
+``QemuLockCnt`` usage
+---------------------
 
 
-This section explains the typical usage patterns for QemuLockCnt functions.
+This section explains the typical usage patterns for ``QemuLockCnt`` functions.
 
 
 Setting a variable to a non-NULL value can be done between
 Setting a variable to a non-NULL value can be done between
-qemu_lockcnt_lock and qemu_lockcnt_unlock:
+``qemu_lockcnt_lock`` and ``qemu_lockcnt_unlock``::
 
 
     qemu_lockcnt_lock(&xyz_lockcnt);
     qemu_lockcnt_lock(&xyz_lockcnt);
     if (!xyz) {
     if (!xyz) {
@@ -193,8 +194,8 @@ qemu_lockcnt_lock and qemu_lockcnt_unlock:
     }
     }
     qemu_lockcnt_unlock(&xyz_lockcnt);
     qemu_lockcnt_unlock(&xyz_lockcnt);
 
 
-Accessing the value can be done between qemu_lockcnt_inc and
-qemu_lockcnt_dec:
+Accessing the value can be done between ``qemu_lockcnt_inc`` and
+``qemu_lockcnt_dec``::
 
 
     qemu_lockcnt_inc(&xyz_lockcnt);
     qemu_lockcnt_inc(&xyz_lockcnt);
     if (xyz) {
     if (xyz) {
@@ -204,11 +205,11 @@ qemu_lockcnt_dec:
     }
     }
     qemu_lockcnt_dec(&xyz_lockcnt);
     qemu_lockcnt_dec(&xyz_lockcnt);
 
 
-Freeing the object can similarly use qemu_lockcnt_lock and
-qemu_lockcnt_unlock, but you also need to ensure that the count
-is zero (i.e. there is no concurrent visit).  Because qemu_lockcnt_inc
-takes the QemuLockCnt's lock, the count cannot become non-zero while
-the object is being freed.  Freeing an object looks like this:
+Freeing the object can similarly use ``qemu_lockcnt_lock`` and
+``qemu_lockcnt_unlock``, but you also need to ensure that the count
+is zero (i.e. there is no concurrent visit).  Because ``qemu_lockcnt_inc``
+takes the ``QemuLockCnt``'s lock, the count cannot become non-zero while
+the object is being freed.  Freeing an object looks like this::
 
 
     qemu_lockcnt_lock(&xyz_lockcnt);
     qemu_lockcnt_lock(&xyz_lockcnt);
     if (!qemu_lockcnt_count(&xyz_lockcnt)) {
     if (!qemu_lockcnt_count(&xyz_lockcnt)) {
@@ -218,7 +219,7 @@ the object is being freed.  Freeing an object looks like this:
     qemu_lockcnt_unlock(&xyz_lockcnt);
     qemu_lockcnt_unlock(&xyz_lockcnt);
 
 
 If an object has to be freed right after a visit, you can combine
 If an object has to be freed right after a visit, you can combine
-the decrement, the locking and the check on count as follows:
+the decrement, the locking and the check on count as follows::
 
 
     qemu_lockcnt_inc(&xyz_lockcnt);
     qemu_lockcnt_inc(&xyz_lockcnt);
     if (xyz) {
     if (xyz) {
@@ -232,7 +233,7 @@ the decrement, the locking and the check on count as follows:
         qemu_lockcnt_unlock(&xyz_lockcnt);
         qemu_lockcnt_unlock(&xyz_lockcnt);
     }
     }
 
 
-QemuLockCnt can also be used to access a list as follows:
+``QemuLockCnt`` can also be used to access a list as follows::
 
 
     qemu_lockcnt_inc(&io_handlers_lockcnt);
     qemu_lockcnt_inc(&io_handlers_lockcnt);
     QLIST_FOREACH_RCU(ioh, &io_handlers, pioh) {
     QLIST_FOREACH_RCU(ioh, &io_handlers, pioh) {
@@ -252,10 +253,10 @@ QemuLockCnt can also be used to access a list as follows:
     }
     }
 
 
 Again, the RCU primitives are used because new items can be added to the
 Again, the RCU primitives are used because new items can be added to the
-list during the walk.  QLIST_FOREACH_RCU ensures that the processor and
+list during the walk.  ``QLIST_FOREACH_RCU`` ensures that the processor and
 the compiler see the appropriate memory barriers.
 the compiler see the appropriate memory barriers.
 
 
-An alternative pattern uses qemu_lockcnt_dec_if_lock:
+An alternative pattern uses ``qemu_lockcnt_dec_if_lock``::
 
 
     qemu_lockcnt_inc(&io_handlers_lockcnt);
     qemu_lockcnt_inc(&io_handlers_lockcnt);
     QLIST_FOREACH_SAFE_RCU(ioh, &io_handlers, next, pioh) {
     QLIST_FOREACH_SAFE_RCU(ioh, &io_handlers, next, pioh) {
@@ -273,5 +274,5 @@ An alternative pattern uses qemu_lockcnt_dec_if_lock:
     }
     }
     qemu_lockcnt_dec(&io_handlers_lockcnt);
     qemu_lockcnt_dec(&io_handlers_lockcnt);
 
 
-Here you can use qemu_lockcnt_dec instead of qemu_lockcnt_dec_and_lock,
+Here you can use ``qemu_lockcnt_dec`` instead of ``qemu_lockcnt_dec_and_lock``,
 because there is no special task to do if the count goes from 1 to 0.
 because there is no special task to do if the count goes from 1 to 0.