rcu: handle forks safely
After forking, only the calling thread is duplicated in the child process. The call_rcu thread has to be recreated in the child. Exploit the fact that only one thread exists (same as when constructors run), and just redo the entire initialization to ensure the threads are in the proper state. The only additional things to do are emptying the list of threads registered with RCU, and unlocking the lock that was taken in the prepare callback (implementations are allowed to fail pthread_mutex_init() if the mutex is still locked). Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
24fa90499f
commit
21b7cf9e07
33
util/rcu.c
33
util/rcu.c
@ -283,7 +283,7 @@ void rcu_unregister_thread(void)
|
|||||||
qemu_mutex_unlock(&rcu_gp_lock);
|
qemu_mutex_unlock(&rcu_gp_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((__constructor__)) rcu_init(void)
|
static void rcu_init_complete(void)
|
||||||
{
|
{
|
||||||
QemuThread thread;
|
QemuThread thread;
|
||||||
|
|
||||||
@ -291,8 +291,39 @@ static void __attribute__((__constructor__)) rcu_init(void)
|
|||||||
qemu_event_init(&rcu_gp_event, true);
|
qemu_event_init(&rcu_gp_event, true);
|
||||||
|
|
||||||
qemu_event_init(&rcu_call_ready_event, false);
|
qemu_event_init(&rcu_call_ready_event, false);
|
||||||
|
|
||||||
|
/* The caller is assumed to have iothread lock, so the call_rcu thread
|
||||||
|
* must have been quiescent even after forking, just recreate it.
|
||||||
|
*/
|
||||||
qemu_thread_create(&thread, "call_rcu", call_rcu_thread,
|
qemu_thread_create(&thread, "call_rcu", call_rcu_thread,
|
||||||
NULL, QEMU_THREAD_DETACHED);
|
NULL, QEMU_THREAD_DETACHED);
|
||||||
|
|
||||||
rcu_register_thread();
|
rcu_register_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_POSIX
|
||||||
|
static void rcu_init_lock(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&rcu_gp_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rcu_init_unlock(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_unlock(&rcu_gp_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rcu_init_child(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_unlock(&rcu_gp_lock);
|
||||||
|
memset(®istry, 0, sizeof(registry));
|
||||||
|
rcu_init_complete();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void __attribute__((__constructor__)) rcu_init(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_POSIX
|
||||||
|
pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_child);
|
||||||
|
#endif
|
||||||
|
rcu_init_complete();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user