The previous release of Cheap Threads (v2.5) introduced a
reference-counting scheme to
reduce the churning of memory associated with the delivery of messages.
Unfortunately that change introduced a memory leak in some circumstances
-- namely,
when the application sends an enqueue rather than a message with any
content. An
enqueue tells the scheduler to enqueue a thread for execution but does
not pass
it any message content, not even zero-length content.
The new scheme makes each thread responsible for deleting the event
associated with
the message, and uses reference counting to avoid deleting the same
event more than
once. The problem was that an enqueue is treated differently. A thread
has no access
to the associated event and cannot delete it. Oops.
The solution is to let the scheduler delete any event associated with an
enqueue.
This fix is confined to a single function, namely
dispatch_event_queue(). Identical
copies of this function appear in the two versions of the scheduler
module: ctsched.c
(for standard Cheap Threads) and ectsched.c (for embedded Cheap
Threads). The new
version of this function is below. (Yahoo's web interface to this
mailing list
suppresses indentation, or (if you look at the HTML source) uglifies it
with HTML tags.
The email version should look okay.)
/****************************************************************
Dispatch all the pending events.
***************************************************************/
static void dispatch_event_queue( void )
{
Ct_event * pE;
while( ev_head != NULL )
{
/* Detach event from queue */
pE = ev_head;
ASSERT( EVENT_MAGIC == pE->magic );
ev_head = ev_head->pNext;
pE->pNext = NULL;
/* Dispatch event according to type */
switch( pE->dispatch_type )
{
case CT_DISPATCH_ADDRESSEE :
dispatch_addressee( pE );
break;
case CT_DISPATCH_SUBSCRIBER :
ct_dispatch_subscription( pE );
break;
case CT_DISPATCH_ALL :
dispatch_all( pE );
break;
default :
ct_report_error( "dispatch_queue: Illegal event type" );
ct_fatal_error();
break;
}
if( CT_EV_ENQ == pE->ev_type )
{
/* For an enqueue we don't attach the event to any */
/* threads, so we can't rely on the threads to */
/* destruct it. Destruct it now. */
ct_destruct_event( &pE );
}
}
ev_tail = NULL;
/* If the current thread sent an event to itself, we */
/* didn't enqueue it yet. Now that we have enqueued */
/* all other recipients, enqueue the current thread. */
if( self_msg )
{
int saved_priority;
ASSERT( pCurr_thread != NULL );
ASSERT( CT_MAGIC == pCurr_thread->magic );
/* Detach the thread from whatever queue it's on */
pCurr_thread->pPrev->pNext = pCurr_thread->pNext;
pCurr_thread->pNext->pPrev = pCurr_thread->pPrev;
/* Enqueue it at the highest priority */
saved_priority = pCurr_thread->priority;
pCurr_thread->priority = 0;
insert_thread( pCurr_thread );
pCurr_thread->priority = saved_priority;
self_msg = 0;
}
}
The change is in the second part of the while loop, where for enqueues
we call
ct_destruct_event().
I have not yet posted this fix on the website, but I hope to do so later
today.
Scott McKellar mck9@...
http://home.swbell.net/mck9/ct/