rcu: Implement drain_call_rcu
This will allow is to preserve the semantics of hmp_device_del, that the device is deleted immediatly which was changed by previos patch that delayed this to RCU callback Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Suggested-by: Stefan Hajnoczi <stefanha@gmail.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20200915121318.247-2-luoyonggang@gmail.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
37d98abdc7
commit
d816614ca4
@ -133,6 +133,7 @@ struct rcu_head {
|
||||
};
|
||||
|
||||
extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
|
||||
extern void drain_call_rcu(void);
|
||||
|
||||
/* The operands of the minus operator must have the same type,
|
||||
* which must be the one that we specify in the cast.
|
||||
|
55
util/rcu.c
55
util/rcu.c
@ -293,6 +293,61 @@ void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node))
|
||||
qemu_event_set(&rcu_call_ready_event);
|
||||
}
|
||||
|
||||
|
||||
struct rcu_drain {
|
||||
struct rcu_head rcu;
|
||||
QemuEvent drain_complete_event;
|
||||
};
|
||||
|
||||
static void drain_rcu_callback(struct rcu_head *node)
|
||||
{
|
||||
struct rcu_drain *event = (struct rcu_drain *)node;
|
||||
qemu_event_set(&event->drain_complete_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function ensures that all pending RCU callbacks
|
||||
* on the current thread are done executing
|
||||
|
||||
* drops big qemu lock during the wait to allow RCU thread
|
||||
* to process the callbacks
|
||||
*
|
||||
*/
|
||||
|
||||
void drain_call_rcu(void)
|
||||
{
|
||||
struct rcu_drain rcu_drain;
|
||||
bool locked = qemu_mutex_iothread_locked();
|
||||
|
||||
memset(&rcu_drain, 0, sizeof(struct rcu_drain));
|
||||
qemu_event_init(&rcu_drain.drain_complete_event, false);
|
||||
|
||||
if (locked) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RCU callbacks are invoked in the same order as in which they
|
||||
* are registered, thus we can be sure that when 'drain_rcu_callback'
|
||||
* is called, all RCU callbacks that were registered on this thread
|
||||
* prior to calling this function are completed.
|
||||
*
|
||||
* Note that since we have only one global queue of the RCU callbacks,
|
||||
* we also end up waiting for most of RCU callbacks that were registered
|
||||
* on the other threads, but this is a side effect that shoudn't be
|
||||
* assumed.
|
||||
*/
|
||||
|
||||
call_rcu1(&rcu_drain.rcu, drain_rcu_callback);
|
||||
qemu_event_wait(&rcu_drain.drain_complete_event);
|
||||
|
||||
if (locked) {
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void rcu_register_thread(void)
|
||||
{
|
||||
assert(rcu_reader.ctr == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user