qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

replay: implement fair mutex

In record/replay icount mode main loop thread and vCPU thread
do not perform simultaneously. They take replay mutex to synchronize
the actions. Sometimes vCPU thread waits for locking the mutex for
very long time, because main loop releases the mutex and takes it
back again. Standard qemu mutex do not provide the ordering
capabilities.

This patch adds a "queue" for replay mutex. Therefore thread ordering
becomes more "fair". Threads are executed in the same order as
they are trying to take the mutex.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Message-Id: <158823802979.28101.9340462887738957616.stgit@pasha-ThinkPad-X280>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Pavel Dovgalyuk and committed by
Paolo Bonzini
ddf63df7 2356ff85

+14 -1
+14 -1
replay/replay-internal.c
··· 22 22 It also protects replay events queue which stores events to be 23 23 written or read to the log. */ 24 24 static QemuMutex lock; 25 + /* Condition and queue for fair ordering of mutex lock requests. */ 26 + static QemuCond mutex_cond; 27 + static unsigned long mutex_head, mutex_tail; 25 28 26 29 /* File for replay writing */ 27 30 static bool write_error; ··· 197 200 void replay_mutex_init(void) 198 201 { 199 202 qemu_mutex_init(&lock); 203 + qemu_cond_init(&mutex_cond); 200 204 /* Hold the mutex while we start-up */ 201 - qemu_mutex_lock(&lock); 202 205 replay_locked = true; 206 + ++mutex_tail; 203 207 } 204 208 205 209 bool replay_mutex_locked(void) ··· 211 215 void replay_mutex_lock(void) 212 216 { 213 217 if (replay_mode != REPLAY_MODE_NONE) { 218 + unsigned long id; 214 219 g_assert(!qemu_mutex_iothread_locked()); 215 220 g_assert(!replay_mutex_locked()); 216 221 qemu_mutex_lock(&lock); 222 + id = mutex_tail++; 223 + while (id != mutex_head) { 224 + qemu_cond_wait(&mutex_cond, &lock); 225 + } 217 226 replay_locked = true; 227 + qemu_mutex_unlock(&lock); 218 228 } 219 229 } 220 230 ··· 222 232 { 223 233 if (replay_mode != REPLAY_MODE_NONE) { 224 234 g_assert(replay_mutex_locked()); 235 + qemu_mutex_lock(&lock); 236 + ++mutex_head; 225 237 replay_locked = false; 238 + qemu_cond_broadcast(&mutex_cond); 226 239 qemu_mutex_unlock(&lock); 227 240 } 228 241 }