include: Move QemuLockCnt APIs to their own header
Currently the QemuLockCnt data structure and associated functions are in the include/qemu/thread.h header. Move them to their own qemu/lockcnt.h. The main reason for doing this is that it means we can autogenerate the documentation comments into the docs/devel documentation. The copyright/author in the new header is drawn from lockcnt.c, since the header changes were added in the same commit as lockcnt.c; since neither thread.h nor lockcnt.c state an explicit license, the standard default of GPL-2-or-later applies. We include the new header (and the .c file, which was accidentally omitted previously) in the "RCU" part of MAINTAINERS, since that is where the lockcnt.rst documentation is categorized. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 20240816132212.3602106-7-peter.maydell@linaro.org
This commit is contained in:
parent
90655d815a
commit
51483f6c84
@ -3061,8 +3061,10 @@ S: Maintained
|
||||
F: docs/devel/lockcnt.rst
|
||||
F: docs/devel/rcu.rst
|
||||
F: include/qemu/rcu*.h
|
||||
F: include/qemu/lockcnt.h
|
||||
F: tests/unit/rcutorture.c
|
||||
F: tests/unit/test-rcu-*.c
|
||||
F: util/lockcnt.c
|
||||
F: util/rcu.c
|
||||
|
||||
Human Monitor (HMP)
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "hw/core/cpu.h"
|
||||
|
@ -175,7 +175,7 @@ three instructions in the critical path, two assignments and a ``smp_wmb()``.
|
||||
``QemuLockCnt`` API
|
||||
-------------------
|
||||
|
||||
The ``QemuLockCnt`` API is described in ``include/qemu/thread.h``.
|
||||
The ``QemuLockCnt`` API is described in ``include/qemu/lockcnt.h``.
|
||||
|
||||
|
||||
``QemuLockCnt`` usage
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "qemu/coroutine-core.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "block/graph-lock.h"
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
|
130
include/qemu/lockcnt.h
Normal file
130
include/qemu/lockcnt.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QemuLockCnt implementation
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2017
|
||||
*
|
||||
* Author:
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QEMU_LOCKCNT_H
|
||||
#define QEMU_LOCKCNT_H
|
||||
|
||||
#include "qemu/thread.h"
|
||||
|
||||
typedef struct QemuLockCnt QemuLockCnt;
|
||||
|
||||
struct QemuLockCnt {
|
||||
#ifndef CONFIG_LINUX
|
||||
QemuMutex mutex;
|
||||
#endif
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_init: initialize a QemuLockcnt
|
||||
* @lockcnt: the lockcnt to initialize
|
||||
*
|
||||
* Initialize lockcnt's counter to zero and prepare its mutex
|
||||
* for usage.
|
||||
*/
|
||||
void qemu_lockcnt_init(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_destroy: destroy a QemuLockcnt
|
||||
* @lockcnt: the lockcnt to destruct
|
||||
*
|
||||
* Destroy lockcnt's mutex.
|
||||
*/
|
||||
void qemu_lockcnt_destroy(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_inc: increment a QemuLockCnt's counter
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* If the lockcnt's count is zero, wait for critical sections
|
||||
* to finish and increment lockcnt's count to 1. If the count
|
||||
* is not zero, just increment it.
|
||||
*
|
||||
* Because this function can wait on the mutex, it must not be
|
||||
* called while the lockcnt's mutex is held by the current thread.
|
||||
* For the same reason, qemu_lockcnt_inc can also contribute to
|
||||
* AB-BA deadlocks. This is a sample deadlock scenario:
|
||||
*
|
||||
* thread 1 thread 2
|
||||
* -------------------------------------------------------
|
||||
* qemu_lockcnt_lock(&lc1);
|
||||
* qemu_lockcnt_lock(&lc2);
|
||||
* qemu_lockcnt_inc(&lc2);
|
||||
* qemu_lockcnt_inc(&lc1);
|
||||
*/
|
||||
void qemu_lockcnt_inc(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec: decrement a QemuLockCnt's counter
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*/
|
||||
void qemu_lockcnt_dec(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and
|
||||
* possibly lock it.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* Decrement lockcnt's count. If the new count is zero, lock
|
||||
* the mutex and return true. Otherwise, return false.
|
||||
*/
|
||||
bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and
|
||||
* lock it.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* If the count is 1, decrement the count to zero, lock
|
||||
* the mutex and return true. Otherwise, return false.
|
||||
*/
|
||||
bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_lock: lock a QemuLockCnt's mutex.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* Remember that concurrent visits are not blocked unless the count is
|
||||
* also zero. You can use qemu_lockcnt_count to check for this inside a
|
||||
* critical section.
|
||||
*/
|
||||
void qemu_lockcnt_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_unlock: release a QemuLockCnt's mutex.
|
||||
* @lockcnt: the lockcnt to operate on.
|
||||
*/
|
||||
void qemu_lockcnt_unlock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt.
|
||||
* @lockcnt: the lockcnt to operate on.
|
||||
*
|
||||
* This is the same as
|
||||
*
|
||||
* qemu_lockcnt_unlock(lockcnt);
|
||||
* qemu_lockcnt_inc(lockcnt);
|
||||
*
|
||||
* but more efficient.
|
||||
*/
|
||||
void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_count: query a LockCnt's count.
|
||||
* @lockcnt: the lockcnt to query.
|
||||
*
|
||||
* Note that the count can change at any time. Still, while the
|
||||
* lockcnt is locked, one can usefully check whether the count
|
||||
* is non-zero.
|
||||
*/
|
||||
unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt);
|
||||
|
||||
#endif
|
@ -293,115 +293,4 @@ static inline void qemu_spin_unlock(QemuSpin *spin)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct QemuLockCnt {
|
||||
#ifndef CONFIG_LINUX
|
||||
QemuMutex mutex;
|
||||
#endif
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_init: initialize a QemuLockcnt
|
||||
* @lockcnt: the lockcnt to initialize
|
||||
*
|
||||
* Initialize lockcnt's counter to zero and prepare its mutex
|
||||
* for usage.
|
||||
*/
|
||||
void qemu_lockcnt_init(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_destroy: destroy a QemuLockcnt
|
||||
* @lockcnt: the lockcnt to destruct
|
||||
*
|
||||
* Destroy lockcnt's mutex.
|
||||
*/
|
||||
void qemu_lockcnt_destroy(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_inc: increment a QemuLockCnt's counter
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* If the lockcnt's count is zero, wait for critical sections
|
||||
* to finish and increment lockcnt's count to 1. If the count
|
||||
* is not zero, just increment it.
|
||||
*
|
||||
* Because this function can wait on the mutex, it must not be
|
||||
* called while the lockcnt's mutex is held by the current thread.
|
||||
* For the same reason, qemu_lockcnt_inc can also contribute to
|
||||
* AB-BA deadlocks. This is a sample deadlock scenario:
|
||||
*
|
||||
* thread 1 thread 2
|
||||
* -------------------------------------------------------
|
||||
* qemu_lockcnt_lock(&lc1);
|
||||
* qemu_lockcnt_lock(&lc2);
|
||||
* qemu_lockcnt_inc(&lc2);
|
||||
* qemu_lockcnt_inc(&lc1);
|
||||
*/
|
||||
void qemu_lockcnt_inc(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec: decrement a QemuLockCnt's counter
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*/
|
||||
void qemu_lockcnt_dec(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and
|
||||
* possibly lock it.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* Decrement lockcnt's count. If the new count is zero, lock
|
||||
* the mutex and return true. Otherwise, return false.
|
||||
*/
|
||||
bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and
|
||||
* lock it.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* If the count is 1, decrement the count to zero, lock
|
||||
* the mutex and return true. Otherwise, return false.
|
||||
*/
|
||||
bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_lock: lock a QemuLockCnt's mutex.
|
||||
* @lockcnt: the lockcnt to operate on
|
||||
*
|
||||
* Remember that concurrent visits are not blocked unless the count is
|
||||
* also zero. You can use qemu_lockcnt_count to check for this inside a
|
||||
* critical section.
|
||||
*/
|
||||
void qemu_lockcnt_lock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_unlock: release a QemuLockCnt's mutex.
|
||||
* @lockcnt: the lockcnt to operate on.
|
||||
*/
|
||||
void qemu_lockcnt_unlock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt.
|
||||
* @lockcnt: the lockcnt to operate on.
|
||||
*
|
||||
* This is the same as
|
||||
*
|
||||
* qemu_lockcnt_unlock(lockcnt);
|
||||
* qemu_lockcnt_inc(lockcnt);
|
||||
*
|
||||
* but more efficient.
|
||||
*/
|
||||
void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt);
|
||||
|
||||
/**
|
||||
* qemu_lockcnt_count: query a LockCnt's count.
|
||||
* @lockcnt: the lockcnt to query.
|
||||
*
|
||||
* Note that the count can change at any time. Still, while the
|
||||
* lockcnt is locked, one can usefully check whether the count
|
||||
* is non-zero.
|
||||
*/
|
||||
unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt);
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "block/block.h"
|
||||
#include "block/thread-pool.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "qemu/sockets.h"
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/block.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "block/graph-lock.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "block/raw-aio.h"
|
||||
#include "qemu/coroutine_int.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/epoll.h>
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "aio-posix.h"
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/lockcnt.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "trace.h"
|
||||
|
Loading…
Reference in New Issue
Block a user