File:  [Qemu by Fabrice Bellard] / qemu / qemu-coroutine-lock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:16:53 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  * coroutine queues and locks
    3:  *
    4:  * Copyright (c) 2011 Kevin Wolf <kwolf@redhat.com>
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: 
   25: #include "qemu-common.h"
   26: #include "qemu-coroutine.h"
   27: #include "qemu-coroutine-int.h"
   28: #include "qemu-queue.h"
   29: #include "main-loop.h"
   30: #include "trace.h"
   31: 
   32: static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
   33:     QTAILQ_HEAD_INITIALIZER(unlock_bh_queue);
   34: static QEMUBH* unlock_bh;
   35: 
   36: static void qemu_co_queue_next_bh(void *opaque)
   37: {
   38:     Coroutine *next;
   39: 
   40:     trace_qemu_co_queue_next_bh();
   41:     while ((next = QTAILQ_FIRST(&unlock_bh_queue))) {
   42:         QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next);
   43:         qemu_coroutine_enter(next, NULL);
   44:     }
   45: }
   46: 
   47: void qemu_co_queue_init(CoQueue *queue)
   48: {
   49:     QTAILQ_INIT(&queue->entries);
   50: 
   51:     if (!unlock_bh) {
   52:         unlock_bh = qemu_bh_new(qemu_co_queue_next_bh, NULL);
   53:     }
   54: }
   55: 
   56: void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
   57: {
   58:     Coroutine *self = qemu_coroutine_self();
   59:     QTAILQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
   60:     qemu_coroutine_yield();
   61:     assert(qemu_in_coroutine());
   62: }
   63: 
   64: bool qemu_co_queue_next(CoQueue *queue)
   65: {
   66:     Coroutine *next;
   67: 
   68:     next = QTAILQ_FIRST(&queue->entries);
   69:     if (next) {
   70:         QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
   71:         QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next);
   72:         trace_qemu_co_queue_next(next);
   73:         qemu_bh_schedule(unlock_bh);
   74:     }
   75: 
   76:     return (next != NULL);
   77: }
   78: 
   79: bool qemu_co_queue_empty(CoQueue *queue)
   80: {
   81:     return (QTAILQ_FIRST(&queue->entries) == NULL);
   82: }
   83: 
   84: void qemu_co_mutex_init(CoMutex *mutex)
   85: {
   86:     memset(mutex, 0, sizeof(*mutex));
   87:     qemu_co_queue_init(&mutex->queue);
   88: }
   89: 
   90: void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
   91: {
   92:     Coroutine *self = qemu_coroutine_self();
   93: 
   94:     trace_qemu_co_mutex_lock_entry(mutex, self);
   95: 
   96:     while (mutex->locked) {
   97:         qemu_co_queue_wait(&mutex->queue);
   98:     }
   99: 
  100:     mutex->locked = true;
  101: 
  102:     trace_qemu_co_mutex_lock_return(mutex, self);
  103: }
  104: 
  105: void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
  106: {
  107:     Coroutine *self = qemu_coroutine_self();
  108: 
  109:     trace_qemu_co_mutex_unlock_entry(mutex, self);
  110: 
  111:     assert(mutex->locked == true);
  112:     assert(qemu_in_coroutine());
  113: 
  114:     mutex->locked = false;
  115:     qemu_co_queue_next(&mutex->queue);
  116: 
  117:     trace_qemu_co_mutex_unlock_return(mutex, self);
  118: }
  119: 
  120: void qemu_co_rwlock_init(CoRwlock *lock)
  121: {
  122:     memset(lock, 0, sizeof(*lock));
  123:     qemu_co_queue_init(&lock->queue);
  124: }
  125: 
  126: void qemu_co_rwlock_rdlock(CoRwlock *lock)
  127: {
  128:     while (lock->writer) {
  129:         qemu_co_queue_wait(&lock->queue);
  130:     }
  131:     lock->reader++;
  132: }
  133: 
  134: void qemu_co_rwlock_unlock(CoRwlock *lock)
  135: {
  136:     assert(qemu_in_coroutine());
  137:     if (lock->writer) {
  138:         lock->writer = false;
  139:         while (!qemu_co_queue_empty(&lock->queue)) {
  140:             /*
  141:              * Wakeup every body. This will include some
  142:              * writers too.
  143:              */
  144:             qemu_co_queue_next(&lock->queue);
  145:         }
  146:     } else {
  147:         lock->reader--;
  148:         assert(lock->reader >= 0);
  149:         /* Wakeup only one waiting writer */
  150:         if (!lock->reader) {
  151:             qemu_co_queue_next(&lock->queue);
  152:         }
  153:     }
  154: }
  155: 
  156: void qemu_co_rwlock_wrlock(CoRwlock *lock)
  157: {
  158:     while (lock->writer || lock->reader) {
  159:         qemu_co_queue_wait(&lock->queue);
  160:     }
  161:     lock->writer = true;
  162: }

unix.superglobalmegacorp.com