private void CleanupCallback()
{
// Called when the cleanup-timer ticks over.
//
// This is the automatic prunning method. Every period, we will perform a two-step
// process. First, for the objects above MinPool, we will obtain the semaphore for
// the object and then destroy it if it was on the old stack. We will continue this
// until we either reach MinPool size, or we are unable to obtain a free object, or
// until we have exhausted all the objects on the old stack. After that, push all
// objects on the new stack to the old stack. So, every period the objects on the
// old stack are destroyed and the objects on the new stack are pushed to the old
// stack. All objects that are currently out and in use are not on either stack.
// With this logic, a object is prunned if unused for at least one period but not
// more than two periods.
// Destroy free objects above MinPool size from old stack.
while(Count > MinPoolSize) { // While above MinPoolSize...
if (Semaphore.WaitOne(0, false) ) { // != WaitTimeout
// We obtained a objects from the semaphore.
PooledStream pooledStream = (PooledStream) m_StackOld.Pop();
if (null != pooledStream) {
// If we obtained one from the old stack, destroy it.
Destroy(pooledStream);
}
else {
// Else we exhausted the old stack, so break.
Semaphore.ReleaseSemaphore();
break;
}
}
else break;
}
// Push to the old-stack. For each free object, move object from new stack
// to old stack.
if(Semaphore.WaitOne(0, false)) { // != WaitTimeout
for(;;) {
PooledStream pooledStream = (PooledStream) m_StackNew.Pop();
if (null == pooledStream)
break;
GlobalLog.Assert(!pooledStream.IsEmancipated, "Pooled object not in pool.");
GlobalLog.Assert(pooledStream.CanBePooled, "Pooled object is not poolable.");
m_StackOld.Push(pooledStream);
}
Semaphore.ReleaseSemaphore();
}
}