/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; } } }
/** * 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); } }