/*
 * voipTimerManager.cpp
 *
 * Copyright (C) 2005, Ranch Networks, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * Author : Srivatsa Chivukula <srivatsa@ranchnetworks.com>
 *
 */

#include <stdlib.h>

#ifdef POSIX
#include <string.h>
#include <stdio.h>
#endif

#include "sysError.h"
#include "voipTimerManager.h"


VoipTimerManager::VoipTimerManager(void)
{
   if( this == 0 )
     return;

   m_lock.create();
   m_pre_handler = 0;
   m_timer_on = 0;
   m_tic = 0;
   m_tic_counter = 0;
   m_eTimer_p = 0;
   memset( (char*)&m_pTimerQ, 0, sizeof( timerQueue_t ) );
   memset( (char*)&m_eTimerQ, 0, sizeof( timerQueue_t ) );

   // These are default allocation routines.
   m_alloc = (ALLOCATOR)malloc;
   m_free  = (DEALLOCATOR)free;

}

VoipTimerManager::VoipTimerManager( ALLOCATOR alloc_p, 
                          DEALLOCATOR free_p,
                          PRE_HANDLER prehandler )
{

	if( this == 0 )
     return;

   m_lock.create(0);
   m_pre_handler = 0;
   m_timer_on = 0;
   m_tic = 0;
   m_tic_counter = 0;
   m_eTimer_p = 0;
   memset( (char*)&m_pTimerQ, 0, sizeof( timerQueue_t ) );
   memset( (char*)&m_eTimerQ, 0, sizeof( timerQueue_t ) );

   if( alloc_p && free_p )
   {
      m_alloc = alloc_p;
      m_free = free_p;
   }
   else
   {
      // These are default allocation routines.
      m_alloc = (ALLOCATOR)malloc;
      m_free  = (DEALLOCATOR)free;
   }

   if( prehandler )
   {
     m_pre_handler = prehandler;
   }

}

unsigned long VoipTimerManager::preHandler( TIMER_HANDLER handler_p,
                                        void *context, 
                                        size_t context_size )
{
    // The semaphore is already released that protects
    // the list and all the contents of the node in the
    // list. There is no way to know if
    // user had freed context ptr or not.
    // No one should at any time modify this routine
    // such that it accesses mem pointed by "context"
    if( handler_p )
       return handler_p( context, context_size );

    return SYS_SUCCESS;
}

VoipTimerManager::~VoipTimerManager(void)
{
   // If there are timers already running then user should
   // clear them by shutdown() call.
   m_timer_on = 0;
   m_tic = 0;
   m_tic_counter = 0;
}

int VoipTimerManager::insertTimer( timerNode_t *node_p )
{
   unsigned long accumulator;
   timerNode_t *insert_p;
   unsigned long timeout_value;
   unsigned long rc;

   if( node_p == 0 )
     return -SYS_EINVPTR;

   if( node_p->intervalSelector == NIL_INTERVAL )
      return -SYS_EINVPARM;

   node_p->next = 0;
   node_p->prev = 0;

   if( node_p->intervalSelector == INITIAL_INTERVAL )
      timeout_value = node_p->timer.initialInterval;
   else
      timeout_value = node_p->timer.repeatInterval;

   if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS  ) 
   { 
      // Generate Swerr here. 
      return rc; 
   }

   if( ( m_pTimerQ.head == 0 ) && ( m_pTimerQ.tail == 0 ) )
   {
      // Insert at the begining
      m_pTimerQ.head = node_p;
      m_pTimerQ.tail = node_p;

      node_p->remainingTime = timeout_value;
      m_pTimerQ.cumulativeTime = timeout_value;
      m_lock.release();

      return SYS_SUCCESS;
   }

   if( m_pTimerQ.cumulativeTime <= timeout_value )
   {
       // Insert at the end

       m_pTimerQ.tail->next = node_p;
       node_p->prev = m_pTimerQ.tail;
       m_pTimerQ.tail = node_p;
       
       node_p->remainingTime = timeout_value - m_pTimerQ.cumulativeTime;
       m_pTimerQ.cumulativeTime = timeout_value;
       m_lock.release();

       return SYS_SUCCESS;
   }

   insert_p = m_pTimerQ.head;
   accumulator = 0;
   while( insert_p )
   {
      accumulator += insert_p->remainingTime;

      if( node_p->intervalSelector == INITIAL_INTERVAL )
         timeout_value = node_p->timer.initialInterval;
      else
         timeout_value = node_p->timer.repeatInterval;

      if( timeout_value < accumulator )
      {
          node_p->next = insert_p;
          if( insert_p->prev != 0 )
          {
             // Adjust the accumulator to be less than the value
             // of timer to be inserted.
             accumulator -= insert_p->remainingTime;
             
             insert_p->prev->next = node_p;
             node_p->remainingTime = timeout_value - accumulator;
          }
          else
          {
             m_pTimerQ.head = node_p;            
             node_p->remainingTime = timeout_value;
          }

          node_p->prev = insert_p->prev;
          insert_p->prev = node_p;
          if( node_p->next )
             node_p->next->remainingTime -= node_p->remainingTime;
          m_lock.release();

          return SYS_SUCCESS;
      }
      insert_p = insert_p->next; 
   }

   // Generate SWERR here. it can happen only when the data is corrupt
   m_lock.release();

   return -SYS_CFAILURE;

}

int VoipTimerManager::flushTimerQueue( timerQueue_t *p, 
                                           unsigned long owner,
                                            unsigned long force )
{
   unsigned long rc;
   timerNode_t *node_p, *nnode_p;
   
   if( p == 0 )
      return -SYS_EINVPTR;

   if( force == 0 )
   {
      if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
      { 
         // Generate Swerr here. 
         return rc; 
      }
   }
   {
      // C R I T I C A L - R E G I O N - B E G I N
      node_p = p->head;

      while( node_p )
      {
         /* if( node_p->owner == owner ) */
         if (1)
         {
             if( node_p->prev != 0 )
               node_p->prev->next = node_p->next;
             if( node_p->next != 0 )
               node_p->next->prev = node_p->prev;
             if( p->head == node_p )
               p->head = p->head->next;
             if( p->tail == node_p )
               p->tail = p->tail->prev;
          
             nnode_p = node_p;
             node_p = node_p->next;
   
             if( nnode_p->timer.cleanup )
               nnode_p->timer.cleanup( TIMER_CANCELLED, 
                                 nnode_p->timer.context,
                                 nnode_p->timer.contextSize );
   
             // Use the free routine to release memory
             if( m_free )
               m_free( nnode_p );
         }
         else 
           node_p = node_p->next;
      }
      // C R I T I C A L - R E G I O N - E N D
   }
   if( force == 0 )
      m_lock.release();

   return SYS_SUCCESS;
}

int VoipTimerManager::flushTimerQueue( timerQueue_t *p, 
                                    unsigned long force )
{
   unsigned long rc;
   timerNode_t *node_p;

   if( p == 0 )
      return SYS_EINVPTR;

   if( force == 0 )
   {
      if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
      { 
        // Generate Swerr here. 
        return rc; 
      }
   }
   {
      // C R I T I C A L - R E G I O N - B E G I N
      while( p->head )
      {
         node_p = p->head;
         p->head = p->head->next;
   
         if( node_p->timer.cleanup )
           node_p->timer.cleanup( TIMER_CANCELLED, 
                            node_p->timer.context,
                            node_p->timer.contextSize );
   
         // Use the free routine to release memory
         if( m_free )
           m_free( node_p );
      }
      memset( (char*)p, 0, sizeof( timerQueue_t ) );

      // C R I T I C A L - R E G I O N - E N D
   }
   if( force == 0 )
      m_lock.release();

   return SYS_SUCCESS;
}

unsigned long VoipTimerManager::unitTic(void)
{
   return m_tic;
}

unsigned long VoipTimerManager::init(unsigned long tic)
{
   unsigned long rc;

   if( tic < MIN_CLOCK_TIC )
      return SYS_EINVPARM;

   // Allow re-initialization after shutdown
   // as shutdown destroys the mutext semaphore.
   if( m_lock.handle() == SEMAPHORE_IS_INVALID )
     m_lock.create();

   if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
   { 
      // Generate Swerr here. 
      return rc; 
   }
   {
      // C R I T I C A L - R E G I O N - B E G I N
      // Clear all previous timers
#ifndef POSIX
      rc = flush();
#endif
      if( rc == SYS_SUCCESS )
      {   
         m_tic_counter = 0;
         m_tic = tic;
         m_timer_on = 1;
	 a = 5;
      }
      // C R I T I C A L - R E G I O N - E N D
   }
   m_lock.release();
   return rc;
}

void VoipTimerManager::tic(void)
{
    timerNode_t *p;

    if( m_timer_on == 0 )
      return ;

    if( m_lock.grab( WAIT_FOREVER ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return ; 
    }
    {
       // C R I T I C A L - R E G I O N - B E G I N
       m_tic_counter++;
       if( m_pTimerQ.head )
       {
          m_pTimerQ.cumulativeTime--;
          m_pTimerQ.head->remainingTime--;
          if( m_pTimerQ.head->remainingTime == 0 )
          {
             // Atleast one timer got fired. Add it to te execution list
             p = m_pTimerQ.head;
   
             while( p && p->remainingTime == 0 ) 
             {
                  m_pTimerQ.head = p->next;
                  if( m_pTimerQ.head != 0 )
                  {
                     // Reset the prev pointer as this node is the 
                     // head of the list.
                     m_pTimerQ.head->prev = 0;
                  }
                  else
                    m_pTimerQ.tail = 0;
   
                  p->prev = 0;
                  p->next = 0;
   
                  // Add it to the execution list
                  if( m_eTimerQ.head == 0 ) 
                  {
                     // Insert at the begining
                     m_eTimerQ.head = p;
                     m_eTimerQ.tail = p;
                  }
                  else
                  {   
                     p->next = m_eTimerQ.head;
                     m_eTimerQ.head->prev = p;
                     m_eTimerQ.head = p;
                  }   
                  p = m_pTimerQ.head;
             }
          }
       }
    // C R I T I C A L - R E G I O N - E N D
    }
    m_lock.release();

    do
    {
      
        // If semaphore is corrupt then nothing can be done.
       if( m_lock.grab( WAIT_FOREVER ) != SYS_SUCCESS ) 
       {
          // Generate a swerr here.
          return;
       }
       {
           // C R I T I C A L - R E G I O N - B E G I N
           p = m_eTimerQ.head;

           if( p != 0 )
           {             
              // Mark the timer to be busy as we are about
              // execute the user installed call back function
              // when the callback is in execution nothing
              // related to it like context or the handler
              // should change.
              m_eTimer_p = p;

              // Advance the head pointer
              m_eTimerQ.head = p->next;
              if( m_eTimerQ.head == 0 )
                 m_eTimerQ.tail = 0;
              else
              {
                 m_eTimerQ.head->prev = 0;
              }
           }
           // C R I T I C A L - R E G I O N - E N D
       }
       m_lock.release();

       if( p )
       {
          // Call prehandler.
          if( m_pre_handler )
             m_pre_handler( p->timer.handler, 
                           // p->timer.cleanup,
                            p->timer.context, 
                            p->timer.contextSize );
          else
             preHandler( p->timer.handler,
                        // p->timer.cleanup,
                         p->timer.context,
                         p->timer.contextSize );

          // If semaphore is corrupt then nothing can be done.
          if( m_lock.grab( WAIT_FOREVER ) != SYS_SUCCESS ) 
          {
             // Generate a swerr here.
             return ;
          } 
          {  
             // C R I T I C A L - R E G I O N - B E G I N

             // If the timer is cancelled then we got to call 
             // cleanup with different code.
             if( m_eTimer_p == 0 )
             {
                 m_eTimer_p = p;
                 // The user has cancelled the timer.
                 if( m_eTimer_p->timer.cleanup )
                    m_eTimer_p->timer.cleanup( TIMER_CANCELLED, 
                                               m_eTimer_p->timer.context,
                                               m_eTimer_p->timer.contextSize );
                 if( m_free )
                   m_free( m_eTimer_p );
             }
             else
             {
                 if( m_eTimer_p->timer.cleanup )
                    m_eTimer_p->timer.cleanup( TIMER_EXPIRED, 
                                               m_eTimer_p->timer.context,
                                               m_eTimer_p->timer.contextSize );
     
                 if( m_eTimer_p->timer.repeatInterval != 0 ) 
                 {
                    // Once the timer fires it should always use the repeat interval.
                    m_eTimer_p->intervalSelector = REPEAT_INTERVAL;
                    // Add it back to the list of pending timers.
                    insertTimer( m_eTimer_p );
                 }
                 else
                 { 
                    // This is a monoshot , so destroy it.
                    // Use the free routine to release memory
                   if( m_free )
                      m_free( m_eTimer_p );
                 }  
             }

             m_eTimer_p = 0;
             // C R I T I C A L - R E G I O N - E N D
          }
          m_lock.release();
       }
    } while(p);
}

int VoipTimerManager::flush(void)
{
  int rc;

   if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
   { 
      // Generate Swerr here. 
      return rc; 
   }
   {
      if( m_eTimer_p != 0 )
      {
          // The timer is in execution. We cancel
          // it anyway as the user is supposed to 
          // free the context ptr. For repeating
          // timers the context ptr is never freed.
          if( m_free )
             m_free( m_eTimer_p );
          m_eTimer_p = 0;
      }
      // C R I T I C A L - R E G I O N - B E G I N
      rc = flushTimerQueue( &m_pTimerQ, 0);
      rc = flushTimerQueue( &m_eTimerQ, 0);
      // C R I T I C A L - R E G I O N - E N D
   }
   m_lock.release();
   return rc;
}

int VoipTimerManager::shutdown(void)
{
   // Destroy the lock and flush the timer list by force.
   // this should be called only when the task that calls
   // the tic function is dead.
   m_lock.destroy();

   // Since the cleanup routine is executed after the 
   // lock is grabbed the task that tics the timer
   // manager cannot be deleted. If m_eTimer_p is not
   // NULL then the timer task is for sure inside
   // the handler and is dead. We call the cleanup
   // function and it is safe to do that.
   if( m_eTimer_p && m_eTimer_p->timer.cleanup )
       m_eTimer_p->timer.cleanup( TIMER_CANCELLED, 
                                  m_eTimer_p->timer.context,
                                  m_eTimer_p->timer.contextSize );
   if( m_eTimer_p && m_free )
     m_free( m_eTimer_p );   
   flushTimerQueue( &m_pTimerQ, 1);
   flushTimerQueue( &m_eTimerQ, 1);

   return SYS_SUCCESS;
}

int VoipTimerManager::pause(void)
{
   m_timer_on = 0;
   return SYS_SUCCESS;
}

int VoipTimerManager::resume(void)
{
   m_timer_on = 1;
   return SYS_SUCCESS;
}

timer_id_t VoipTimerManager::setTimer( sysTimer_t *t ) 
                                      
{
   timerNode_t *node_p;
   timer_id_t handle;

   if( m_tic == 0 )
      return 0;

   if( ( t == 0 ) )
      return 0;

   if( ( t->initialInterval % m_tic != 0 ) ||
       ( t->repeatInterval % m_tic != 0 ) )
      return 0;

   handle = 0;

   // Use the alloc routine to get memory
   if( m_alloc )
      node_p = (timerNode_t *)malloc( sizeof(timerNode_t) );
   else
      return 0;

   if( node_p == 0 )
       return 0;

   node_p->timer = *t;                       // Copy the values;
   node_p->timer.initialInterval /= m_tic;   // Compute the interval.
   node_p->timer.repeatInterval  /= m_tic;   // in terms of ticks.

   node_p->intervalSelector = INITIAL_INTERVAL;
   node_p->next = 0;
   node_p->prev = 0;
   
   // Now let us use the memory address as the handle;
   node_p->handle = (timer_id_t)node_p;
   handle = node_p->handle;

   insertTimer( node_p );
   return handle;
}

int
VoipTimerManager::getTimer( timer_id_t handle, sysTimer_t *t )
{
    unsigned long rc;
    timerNode_t *p, *q;

    if( t == 0 )
       return SYS_EINVPTR;

    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       *t = m_eTimer_p->timer;
       t->initialInterval *= m_tic;  // Return values 
       t->repeatInterval  *= m_tic;  // in terms of milli secs.

       m_lock.release();
       return SYS_SUCCESS;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;

    while( (p != 0) || (q != 0 ) )
    {
       if( q && ( q->handle == handle ) )
       {
           *t = q->timer;
           t->initialInterval *= m_tic;  // Return values 
           t->repeatInterval  *= m_tic;  // in terms of milli secs.
           m_lock.release();

           return SYS_SUCCESS;
       }

       if( p && ( p->handle == handle ) )
       {
           *t = p->timer;
           t->initialInterval *= m_tic;  // Return values 
           t->repeatInterval  *= m_tic;  // in terms of milli secs.
           m_lock.release();

           return SYS_SUCCESS;
       }
    
       if(p) p = p->next; if(q) q = q->next;
    }
    m_lock.release();

    return -SYS_ENFOUND;
}

int VoipTimerManager::cancelTimer( timer_id_t handle )
{
    unsigned long rc;
    timerNode_t *p, *q;

    // At this point the timer might be in either of
    // pending list or execution list. We need to search
    // both. This can occur because timer manager unlocks
    // the data structures before executing callback 
    // functions. This is done for other tasks that share
    // the timer manager to insert of cancel timers.
    
    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    {  
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       // Cancel the timer. Since the handler is
       // getting executed we just mark it for cancellation.
       // The apropriate cleanup routine is called after
       // handler finishes execution.
       m_eTimer_p = 0;
       m_lock.release();

       // Return SYS_ETIMEOUT because the timer has already
       // fired. This given an indication to the user to
       // handle data shared between the user function and
       // the callback function. 
       return SYS_ETIMEOUT;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;

    while( (p != 0) || (q != 0 ) )
    {
       if( q && ( q->handle == handle ) )
       {
           if( m_free == 0 )
           {
               m_lock.release();
               return SYS_ENRESOURCE;
           }

           if( q->prev != 0 )
           {       
              q->prev->next = q->next;
           }       
           else    
           {
             m_eTimerQ.head = q->next;
           }   

           // Call the user defined cleanup routine
           if( q->timer.cleanup )
              q->timer.cleanup( TIMER_CANCELLED, 
                                q->timer.context,
                                q->timer.contextSize );

           // Use the free routine to release memory 
           if( m_free )   
             m_free( q);

           m_lock.release();
           return SYS_SUCCESS;
       }

       if( p && ( p->handle == handle ) )
       {
           if( m_free == 0 )
           {
               m_lock.release();
               return SYS_ENRESOURCE;
           }

           if( p->prev != 0 )
           {
              p->prev->next = p->next;
           }
           else
           {
             m_pTimerQ.head = p->next;
           }

           if( p->next != 0 )
           {
              p->next->prev = p->prev;
              p->next->remainingTime += p->remainingTime;
           }
           else
		   {
              m_pTimerQ.tail = p->prev;
			  m_pTimerQ.cumulativeTime -= p->remainingTime;
		   }

           // Call the user defined cleanup routine
           if( p->timer.cleanup )
              p->timer.cleanup( TIMER_CANCELLED, 
                                p->timer.context,
                                p->timer.contextSize );
           // Use the free routine to release memory 
           if( m_free )   
             m_free( p);

           m_lock.release();   
           return SYS_SUCCESS;
       }

       if(p) p = p->next; if(q) q = q->next;
    }
    m_lock.release();   
    return SYS_ENFOUND;
}

unsigned long VoipTimerManager::getElapsedTime( timer_id_t handle, int unit )
{
    unsigned long rc;
    unsigned long accumulator;
    timerNode_t *p, *q;
    unsigned long etime=0;

    // Only milliseconds at present.

    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       // The timer has already fired. In this 
       // case elapsed time is same as timer value;
       etime = m_eTimer_p->timer.initialInterval;
       m_lock.release();

       return etime;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;
    accumulator = 0;
    while( (p != 0) || (q != 0 ) )
    {
       // The timer has already fired. In this 
       // case elapsed time is same as timer value;
       if( q && ( q->handle == handle ) )
       {
           if( q->intervalSelector == INITIAL_INTERVAL )
              etime = q->timer.initialInterval;

           if( q->intervalSelector == REPEAT_INTERVAL )
              etime = q->timer.repeatInterval;
           m_lock.release();   

           return etime;
       }

       if( p != 0 )
       {
           // First compute the remaining time
           accumulator += p->remainingTime;
           if( p->handle == handle )
           {
              if( p->intervalSelector == INITIAL_INTERVAL )
                 etime = p->timer.initialInterval - accumulator;

              if( p->intervalSelector == REPEAT_INTERVAL )
                 etime = p->timer.repeatInterval - accumulator;
              m_lock.release();   

              return etime;
           }
       }

       if(p) p = p->next; if(q) q = q->next;
    }
    m_lock.release();   

    return etime;
}

unsigned long VoipTimerManager::getRemainingTime(timer_id_t handle, int unit )
{
    unsigned long rc; 
    unsigned long accumulator;
    timerNode_t *p, *q;
    unsigned long rtime = 0;    

    unit = 0; // Only millisecs at present.

    accumulator = 0;
    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       // The timer has already fired. In this 
       // case elapsed time is same as timer value;
       rtime =0;
       m_lock.release();

       return rtime;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;
    while( (p != 0) || (q != 0 ) )
    {
       // The timer has already fired. In this 
       // case remaining time is zero
       if( q && ( q->handle == handle ) )
       {
           rtime = 0;
           m_lock.release();   

           return rtime;
       }

       if( p )
       {
          accumulator += p->remainingTime;
          if( p->handle == handle )
          {
              rtime = accumulator;
              m_lock.release();   

              return rtime;
          }
       }

       if(p) p = p->next; 
       if(q) q = q->next;
    }
    m_lock.release();   

    return rtime;
}


int VoipTimerManager::setTimerContext( timer_id_t handle, void *cp, size_t cs )
{
    unsigned long rc;
    timerNode_t *p, *q;

    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       // Check if the timer handler is in progress.
       // return SYS_EINUSE       

       m_lock.release();
       return -SYS_EINUSE;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;
    while( (p != 0) || (q != 0 ) )
    {
       if( q && ( q->handle == handle ) )
       {
           q->timer.context = cp;
           q->timer.contextSize = cs;
           m_lock.release();   

           return SYS_SUCCESS;
       }

       if( p && ( p->handle == handle ) )
       {

           p->timer.context = cp;
           p->timer.contextSize = cs;
           m_lock.release();   

           return SYS_SUCCESS;
       }

       if(p) p = p->next; if(q) q = q->next;
    }
    m_lock.release();   
    return -SYS_ENFOUND;
}

int VoipTimerManager::setTimerHandler( timer_id_t handle, 
                                   TIMER_HANDLER handler_p)
{
    unsigned long rc;
    timerNode_t *p, *q;

    if( ( rc = m_lock.grab( WAIT_FOREVER ) ) != SYS_SUCCESS ) 
    { 
       // Generate Swerr here. 
       return rc; 
    }

    if( m_eTimer_p && m_eTimer_p->handle == handle )
    {
       // Check if the timer handler is in progress.
       // return SYS_EINUSE       

       m_lock.release();
       return -SYS_EINUSE;
    }

    p = m_pTimerQ.head;
    q = m_eTimerQ.head;
    while( (p != 0) || (q != 0 ) )
    {
       if( q && ( q->handle == handle ) )
       {
           q->timer.handler = handler_p;
           m_lock.release();   

           return SYS_SUCCESS;
       }

       if( p && ( p->handle == handle ) )
       {
           p->timer.handler = handler_p;
           m_lock.release();   

           return SYS_SUCCESS;
       }
    
       if(p) p = p->next; if(q) q = q->next;
    }
    m_lock.release();   
    return -SYS_ENFOUND;
}
