Exemplo n.º 1
0
/**
 * Converts exclusive lock to non-exclusive without releasing it. The caller
 * must own the lock exclusively.
 */
Bool RWLOCK_DropWrite(RWLock * lock)
{
    Bool success = False;
    RWEntry * entry;

    MUTEX_Lock(&lock->mutex);
    entry = RWLOCK_FindEntry(lock);

    /* current thread must have the lock */
    ASSERT(entry);
    if (entry) {

        /* and it must be the write lock */
        ASSERT(entry->write > 0);
        if (entry->write > 0) {
            QEntry * e;
            RWLockWaiter * shareWaiter = NULL;
            RWLockWaiter * exclusiveWaiter = NULL;

            /* convert write lock to read lock */
            entry->read += entry->write;
            entry->write = 0;

            /* lock is no longer owned exclusively */
            ASSERT(lock->flags & RWLOCK_FLAG_EXCLUSIVE_LOCK);
            lock->flags &= ~RWLOCK_FLAG_EXCLUSIVE_LOCK;

            /*
             * wake up shared waiters only unless the exclusive
             * waiter is first in the line
             */
            e = QUEUE_First(&lock->shareWaiters);
            if (e) shareWaiter = QCAST(e,RWLockWaiter,entry);
            e = QUEUE_First(&lock->exclusiveWaiters);
            if (e) exclusiveWaiter = QCAST(e,RWLockWaiter,entry);

            if (shareWaiter && (!exclusiveWaiter ||
                shareWaiter->index < exclusiveWaiter->index)) {
                EVENT_Set(shareWaiter->event);
            }

            /* success */
            success = True;
        }
    }

    MUTEX_Unlock(&lock->mutex);
    return success;
}
Exemplo n.º 2
0
/**
 * Removes the first entry from the queue.
 * Returns NULL if queue is empty
 */
QEntry * QUEUE_RemoveHead(Queue * q)
{
    QEntry * e = QUEUE_First(q);
    if (e) {
        _RemoveEntry(e);
        _InvalidateEntry(e);
        q->size--;
    }
    return e;
}
Exemplo n.º 3
0
/**
 * Finds port by name. Optionally, adds a reference to the returned port.
 * The search is case insensitive.
 */
EcmtGatewayPort* GWENG_PortByName(EcmtGatewayTransport* t, Str name, Bool ref)
{
    QEntry* e;
    EcmtGatewayPort* port = NULL;
    MUTEX_Lock(&t->mutex);
    for (e = QUEUE_First(&t->ports); e; e = QUEUE_Next(e)) {
        if (!StrCaseCmp(name, QCAST(e,EcmtGatewayPort,entry)->name)) {
            port = QCAST(e,EcmtGatewayPort,entry);
            if (ref) GWENG_PortAddRef(port);
            break;
        }
    }
    MUTEX_Unlock(&t->mutex);
    return port;
}
Exemplo n.º 4
0
/**
 * Creates the iterator
 */
Iterator * QUEUE_Iterator(Queue * q)
{
    if (QUEUE_IsEmpty(q)) {
        return ITR_Empty();
    } else {
        QueueIterator * qi = MEM_New(QueueIterator);
        if (qi) {
            ITR_Init(&qi->itr, &queueIterator);
            qi->entry = NULL;
            qi->next = QUEUE_First(q);
            return &qi->itr;
        } else {
            return NULL;
        }
    }
}
Exemplo n.º 5
0
/**
 * Release n recursively acquired locks.
 */
void RWLOCK_UnlockMany(RWLock * lock, int n) 
{
    if (n > 0) {
        RWEntry * entry;
        MUTEX_Lock(&lock->mutex);
        entry = RWLOCK_FindEntry(lock);

        /*
         * if we cannot find the entry, it means that current thread 
         * does not own the lock. It's a programming error. 
         */
        ASSERT(entry);
        if (entry) {
            lock->locks--;
            
            /* first release write locks */
            if (entry->write > 0) {
                if (entry->write >= n) {
                    entry->write -= n;
                    n = 0;
                } else {
                    n -= entry->write;
                    entry->write = 0;
                }
            }

            /* then read locks */
            if (n > 0) {
                entry->read -= n;
            }

            /* 
             * ASSERT that current thread does not release more locks than 
             * it has acquired
             */
            ASSERT(lock->locks >= 0);
            ASSERT(entry->read >= 0);
            ASSERT(entry->write >= 0);

            /*
             * no more work to do unless calling thread has released the
             * resource (i.e. usage count came down to zero)
             */
            if ((entry->read + entry->write) <= 0) {
                int i;
                int inUse;
                QEntry * e;
                RWLockWaiter * shareWaiter = NULL;
                RWLockWaiter * exclusiveWaiter = NULL;

                entry->id = 0;

                lock->entriesActive--;
                ASSERT(lock->entriesActive >= 0);

                /* 
                 * update lock->entriesInUse
                 * NOTE that RWLOCK_FindStaticEntry() may access it without 
                 * synchronization.
                 */
                i = lock->entriesInUse - 1;
                inUse = 0;
                while (i >= 0) {
                    RWEntry * lockEntry = GET_ENTRY(lock,i);
                    if (lockEntry->id) {
                        inUse = i + 1;
                        break;
                    }
                    i--;
                }

                lock->entriesInUse = inUse;

                /*
                 * if resource was acquired exclusively, it must be free now
                 */
                if (lock->flags & RWLOCK_FLAG_EXCLUSIVE_LOCK) {
                    ASSERT(!lock->locks);
                    lock->flags &= ~RWLOCK_FLAG_EXCLUSIVE_LOCK;
                }

                /* 
                 * release the waiters in the order they have arrived
                 */
                e = QUEUE_First(&lock->shareWaiters);
                if (e) shareWaiter = QCAST(e,RWLockWaiter,entry);
                e = QUEUE_First(&lock->exclusiveWaiters);
                if (e) exclusiveWaiter = QCAST(e,RWLockWaiter,entry);

                if (exclusiveWaiter && (!shareWaiter ||
                    exclusiveWaiter->index < shareWaiter->index)) {
                    EVENT_Set(exclusiveWaiter->event);
                } else if (shareWaiter) {
                    /* this should unblock all shared waiters */
                    EVENT_Set(shareWaiter->event);
                }

            } else if (lock->flags & RWLOCK_FLAG_EXCLUSIVE_LOCK) {

                /*
                 * if the owner of the lock has released all its WRITE locks 
                 * but still have some READ locks, switch to shared mode.
                 */
                if (!entry->write) {            
                    QEntry * e;
                    RWLockWaiter * shareWaiter = NULL;
                    RWLockWaiter * exclusiveWaiter = NULL;

                    ASSERT(entry->read > 0);
                    lock->flags &= ~RWLOCK_FLAG_EXCLUSIVE_LOCK;

                    /*
                     * wake up shared waiters only unless the exclusive
                     * waiter is first in the line
                     */
                    e = QUEUE_First(&lock->shareWaiters);
                    if (e) shareWaiter = QCAST(e,RWLockWaiter,entry);
                    e = QUEUE_First(&lock->exclusiveWaiters);
                    if (e) exclusiveWaiter = QCAST(e,RWLockWaiter,entry);

                    if (shareWaiter && (!exclusiveWaiter ||
                        shareWaiter->index < exclusiveWaiter->index)) {
                        EVENT_Set(shareWaiter->event);
                    }
                }
            }
        }
        MUTEX_Unlock(&lock->mutex);
    }
}