docs: void fireInternalAlarm()
    {
  //  what time is it now?
      long now = System.currentTimeMillis();
      
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        SibTr.entry(tc, "fireInternalAlarm", new Object[] {this, Long.valueOf(now)});
      
      //lock the lists
      synchronized(_firedAlarmsLock)
      {      
        synchronized(_pendingAlarmsLock)
        {
          //find the next alarm to be run
          MPAlarmImpl alarm = (MPAlarmImpl) _pendingAlarms.getFirst();
          //while cancelAll has not been called and
          //      the list of pending alarms is not empty and
          //      the current alarm's target time has been passed
          //        or is earlier than the current batch alarm time 
          while(!_cancelAll && 
                alarm != null && 
                (alarm.time() <= now || 
                 alarm.time() <= _batchAlarmTime))
          {
            //remove the next alarm from the pending list
            _pendingAlarms.remove(alarm);
            //and put it in the list of alarms to be fired
            _firedAlarms.put(alarm);
            //if the batch alarm time has not been set
            //or the latest time for the current alarm is earlier than that
            //of the batch Alarm time
            if(_batchAlarmTime == -1 || alarm.latest() < _batchAlarmTime)
            {
              //set the batch alarm time to be the latest time the current alarm
              //can be run
              _batchAlarmTime = alarm.latest();          
            }
            //get the next alarm in the list, which should now be at the top
            alarm = (MPAlarmImpl) _pendingAlarms.getFirst();
          }//while
          
          //if the last alarm in the list to be fired (if any) has a target
          //time earlier than the batch alarm time 
          alarm = (MPAlarmImpl)_firedAlarms.getLast();
          if(alarm != null && alarm.time() < _batchAlarmTime)
          {
            //set the batch alarm time to be the target time of the last alarm.
            //since it is the last alarm which can be fired, there is no point
            //in leaving the batch alarm time as the latest time for the first
            //alarm in the list ... i.e. fire as soon as possible for the given batch
            _batchAlarmTime = alarm.time();
          }                        
        }//release the pending alarm list lock
        //new alarms can now be added by other threads at the same time
        //as the existing once are being executed
        
        //if we have reach any given batch alarm time      
        if(now >= _batchAlarmTime)
        {
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
          {
            SibTr.debug(tc, "Pending " + _pendingAlarms);
            SibTr.debug(tc, "Firing " + _firedAlarms);
          }
          
          //iterate over the list of alarms to be fired
          //until the list is empty or cancelAll is called
          MPAlarmImpl alarm = (MPAlarmImpl) _firedAlarms.getFirst();
          while(!_cancelAll && alarm != null)
          {
            //remove the current alarm from the list
            _firedAlarms.remove(alarm);
            // Take a copy of the variables from the alarm
            AlarmListener alarmListener = alarm.listener();
            boolean alarmHasGroupListener = alarm.hasGroupListener();
            Object alarmContext = alarm.context();
            boolean alarmIsActive = alarm.active();
            //if it has not been canceled
            if(alarmIsActive && alarmListener != null)
            {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                SibTr.debug(tc, "Alarm Fire : " + alarm);
              
              //if it does not have a group listener
              if(!alarmHasGroupListener)
              {
                try
                {
                  //fire the alarm, passing in it's context object
                  alarmListener.alarm(alarmContext);
                }
                catch(Throwable e)
                {
                  // FFDC the problem with the alarm but swallow the exception
                  // and carry on, in the hope that the ME can limp on regardless
                  FFDCFilter.processException(
                    e,
                    "com.ibm.ws.sib.processor.utils.am.MPAlarmManager.fireInternalAlarm",
                    "1:560:1.28",
                    new Object[] {this, alarmListener, alarmContext});
                  
                  SibTr.exception(tc, e);          
                }
              }//if it does have a group listener which is not in the list for this batch
              else if(!_groupListeners.containsKey(((GroupAlarmListener)alarmListener).getGroupUuid()))
              {
                //put the listener in the list for this batch
                _groupListeners.put(((GroupAlarmListener)alarmListener).getGroupUuid(), alarmListener);
                //start the group alarm sequence, passing in the first alarm context
                ((GroupAlarmListener)alarmListener).beginGroupAlarm(alarmContext);
              }
              else //if it does have a group listener which is already in the list for this batch
              {
                //add the alarm context to the group listener
                ((GroupAlarmListener)alarmListener).addContext(alarmContext);
              }
              // return the alarm object to the pool
              // we only do this in the active case, as if we found the alarm had been
              // cancelled by another thread, it's safer to simply discard the object
              // rather than assuming it's safe for re-use.
              _alarmPool.add(alarm); 
            }
            //get the next alarm to be fired
            alarm = (MPAlarmImpl) _firedAlarms.getFirst();
          }//while
          
          //if group listeners were found in the batch
          if(_groupListeners.size() > 0)
          {
            if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.debug(tc, "GroupListeners size is: " + _groupListeners.size());
            //iterate over the group listeners for this batch
            Set groupNames = _groupListeners.keySet();
            Iterator itr = groupNames.iterator();
            while(itr.hasNext())
            {
              //get the next group listener
              GroupAlarmListener listener =
                (GroupAlarmListener) _groupListeners.get(itr.next());
              try
              {
                //call it's alarm method with a null context
                listener.alarm(null);
              }
              catch(Throwable e)
              {
                // FFDC the problem with the alarm but swallow the exception
                // and carry on, in the hope that the ME can limp on regardless
                FFDCFilter.processException(
                  e,
                  "com.ibm.ws.sib.processor.utils.am.MPAlarmManager.fireInternalAlarm",
                  "1:613:1.28",
                  new Object[] {this, listener});
                
                SibTr.exception(tc, e);          
              }
            }
            if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.debug(tc, "Finished calling group alarms");
            //clear the list of group listeners ready for the next batch
            _groupListeners.clear();        
          }
          //the batch is done so reset the batch alarm time
          _batchAlarmTime = -1;        
        }
        
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
          SibTr.debug(tc, "About to get _pendingAlarmsLock");
        //retake the pending alarms list lock while we work out when the next alarm is      
        synchronized(_pendingAlarmsLock)
        {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.debug(tc, "Got _pendingAlarmsLock");
          //if there is still a pending batch to be run
          if(_batchAlarmTime > -1)
          {
            //use the batch alarm time as the next target wakeup time          
            _nextAlarm = _batchAlarmTime;
          }
          else //otherwise look at the list of pending alarms
          {
            MPAlarmImpl alarm = (MPAlarmImpl)_pendingAlarms.getFirst();
            //if there are not any alarms in the list, set the target time to MPAlarmThread.SUSPEND
            //in order to suspend the alarm thread
            if(alarm == null) _nextAlarm = MPAlarmThread.SUSPEND;
            //if there is at least one pending alarm, the target time is that of
            //the first alarm
            else _nextAlarm = alarm.time();
          }                
        }
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
          SibTr.exit(tc, "fireInternalAlarm", Long.valueOf(_nextAlarm));
      }            
    }