"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "util/qemu-coroutine-lock.c" between
qemu-6.0.0-rc1.tar.xz and qemu-6.0.0-rc2.tar.xz

About: QEMU is a generic machine/processor emulator and virtualizer. Release candidate.

qemu-coroutine-lock.c  (qemu-6.0.0-rc1.tar.xz):qemu-coroutine-lock.c  (qemu-6.0.0-rc2.tar.xz)
skipping to change at line 207 skipping to change at line 207
} }
static void coroutine_fn qemu_co_mutex_lock_slowpath(AioContext *ctx, static void coroutine_fn qemu_co_mutex_lock_slowpath(AioContext *ctx,
CoMutex *mutex) CoMutex *mutex)
{ {
Coroutine *self = qemu_coroutine_self(); Coroutine *self = qemu_coroutine_self();
CoWaitRecord w; CoWaitRecord w;
unsigned old_handoff; unsigned old_handoff;
trace_qemu_co_mutex_lock_entry(mutex, self); trace_qemu_co_mutex_lock_entry(mutex, self);
w.co = self;
push_waiter(mutex, &w); push_waiter(mutex, &w);
/* This is the "Responsibility Hand-Off" protocol; a lock() picks from /* This is the "Responsibility Hand-Off" protocol; a lock() picks from
* a concurrent unlock() the responsibility of waking somebody up. * a concurrent unlock() the responsibility of waking somebody up.
*/ */
old_handoff = qatomic_mb_read(&mutex->handoff); old_handoff = qatomic_mb_read(&mutex->handoff);
if (old_handoff && if (old_handoff &&
has_waiters(mutex) && has_waiters(mutex) &&
qatomic_cmpxchg(&mutex->handoff, old_handoff, 0) == old_handoff) { qatomic_cmpxchg(&mutex->handoff, old_handoff, 0) == old_handoff) {
/* There can be no concurrent pops, because there can be only /* There can be no concurrent pops, because there can be only
skipping to change at line 331 skipping to change at line 330
* already taken it, however, we're done and they're responsible. * already taken it, however, we're done and they're responsible.
*/ */
if (qatomic_cmpxchg(&mutex->handoff, our_handoff, 0) != our_handoff) { if (qatomic_cmpxchg(&mutex->handoff, our_handoff, 0) != our_handoff) {
break; break;
} }
} }
trace_qemu_co_mutex_unlock_return(mutex, self); trace_qemu_co_mutex_unlock_return(mutex, self);
} }
struct CoRwTicket {
bool read;
Coroutine *co;
QSIMPLEQ_ENTRY(CoRwTicket) next;
};
void qemu_co_rwlock_init(CoRwlock *lock) void qemu_co_rwlock_init(CoRwlock *lock)
{ {
memset(lock, 0, sizeof(*lock));
qemu_co_queue_init(&lock->queue);
qemu_co_mutex_init(&lock->mutex); qemu_co_mutex_init(&lock->mutex);
lock->owners = 0;
QSIMPLEQ_INIT(&lock->tickets);
}
/* Releases the internal CoMutex. */
static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock)
{
CoRwTicket *tkt = QSIMPLEQ_FIRST(&lock->tickets);
Coroutine *co = NULL;
/*
* Setting lock->owners here prevents rdlock and wrlock from
* sneaking in between unlock and wake.
*/
if (tkt) {
if (tkt->read) {
if (lock->owners >= 0) {
lock->owners++;
co = tkt->co;
}
} else {
if (lock->owners == 0) {
lock->owners = -1;
co = tkt->co;
}
}
}
if (co) {
QSIMPLEQ_REMOVE_HEAD(&lock->tickets, next);
qemu_co_mutex_unlock(&lock->mutex);
aio_co_wake(co);
} else {
qemu_co_mutex_unlock(&lock->mutex);
}
} }
void qemu_co_rwlock_rdlock(CoRwlock *lock) void qemu_co_rwlock_rdlock(CoRwlock *lock)
{ {
Coroutine *self = qemu_coroutine_self(); Coroutine *self = qemu_coroutine_self();
qemu_co_mutex_lock(&lock->mutex); qemu_co_mutex_lock(&lock->mutex);
/* For fairness, wait if a writer is in line. */ /* For fairness, wait if a writer is in line. */
while (lock->pending_writer) { if (lock->owners == 0 || (lock->owners > 0 && QSIMPLEQ_EMPTY(&lock->tickets)
qemu_co_queue_wait(&lock->queue, &lock->mutex); )) {
lock->owners++;
qemu_co_mutex_unlock(&lock->mutex);
} else {
CoRwTicket my_ticket = { true, self };
QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next);
qemu_co_mutex_unlock(&lock->mutex);
qemu_coroutine_yield();
assert(lock->owners >= 1);
/* Possibly wake another reader, which will wake the next in line. */
qemu_co_mutex_lock(&lock->mutex);
qemu_co_rwlock_maybe_wake_one(lock);
} }
lock->reader++;
qemu_co_mutex_unlock(&lock->mutex);
/* The rest of the read-side critical section is run without the mutex. */
self->locks_held++; self->locks_held++;
} }
void qemu_co_rwlock_unlock(CoRwlock *lock) void qemu_co_rwlock_unlock(CoRwlock *lock)
{ {
Coroutine *self = qemu_coroutine_self(); Coroutine *self = qemu_coroutine_self();
assert(qemu_in_coroutine()); assert(qemu_in_coroutine());
if (!lock->reader) { self->locks_held--;
/* The critical section started in qemu_co_rwlock_wrlock. */
qemu_co_queue_restart_all(&lock->queue);
} else {
self->locks_held--;
qemu_co_mutex_lock(&lock->mutex); qemu_co_mutex_lock(&lock->mutex);
lock->reader--; if (lock->owners > 0) {
assert(lock->reader >= 0); lock->owners--;
/* Wakeup only one waiting writer */ } else {
if (!lock->reader) { assert(lock->owners == -1);
qemu_co_queue_next(&lock->queue); lock->owners = 0;
}
} }
qemu_co_mutex_unlock(&lock->mutex);
qemu_co_rwlock_maybe_wake_one(lock);
} }
void qemu_co_rwlock_downgrade(CoRwlock *lock) void qemu_co_rwlock_downgrade(CoRwlock *lock)
{ {
Coroutine *self = qemu_coroutine_self(); qemu_co_mutex_lock(&lock->mutex);
assert(lock->owners == -1);
/* lock->mutex critical section started in qemu_co_rwlock_wrlock or lock->owners = 1;
* qemu_co_rwlock_upgrade.
*/
assert(lock->reader == 0);
lock->reader++;
qemu_co_mutex_unlock(&lock->mutex);
/* The rest of the read-side critical section is run without the mutex. */ /* Possibly wake another reader, which will wake the next in line. */
self->locks_held++; qemu_co_rwlock_maybe_wake_one(lock);
} }
void qemu_co_rwlock_wrlock(CoRwlock *lock) void qemu_co_rwlock_wrlock(CoRwlock *lock)
{ {
Coroutine *self = qemu_coroutine_self();
qemu_co_mutex_lock(&lock->mutex); qemu_co_mutex_lock(&lock->mutex);
lock->pending_writer++; if (lock->owners == 0) {
while (lock->reader) { lock->owners = -1;
qemu_co_queue_wait(&lock->queue, &lock->mutex); qemu_co_mutex_unlock(&lock->mutex);
} } else {
lock->pending_writer--; CoRwTicket my_ticket = { false, qemu_coroutine_self() };
/* The rest of the write-side critical section is run with QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next);
* the mutex taken, so that lock->reader remains zero. qemu_co_mutex_unlock(&lock->mutex);
* There is no need to update self->locks_held. qemu_coroutine_yield();
*/ assert(lock->owners == -1);
}
self->locks_held++;
} }
void qemu_co_rwlock_upgrade(CoRwlock *lock) void qemu_co_rwlock_upgrade(CoRwlock *lock)
{ {
Coroutine *self = qemu_coroutine_self();
qemu_co_mutex_lock(&lock->mutex); qemu_co_mutex_lock(&lock->mutex);
assert(lock->reader > 0); assert(lock->owners > 0);
lock->reader--; /* For fairness, wait if a writer is in line. */
lock->pending_writer++; if (lock->owners == 1 && QSIMPLEQ_EMPTY(&lock->tickets)) {
while (lock->reader) { lock->owners = -1;
qemu_co_queue_wait(&lock->queue, &lock->mutex); qemu_co_mutex_unlock(&lock->mutex);
} } else {
lock->pending_writer--; CoRwTicket my_ticket = { false, qemu_coroutine_self() };
/* The rest of the write-side critical section is run with lock->owners--;
* the mutex taken, similar to qemu_co_rwlock_wrlock. Do QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next);
* not account for the lock twice in self->locks_held. qemu_co_rwlock_maybe_wake_one(lock);
*/ qemu_coroutine_yield();
self->locks_held--; assert(lock->owners == -1);
}
} }
 End of changes. 16 change blocks. 
56 lines changed or deleted 100 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)