/** {@inheritDoc} */
  protected void getNewMonitors(Map<String, Monitor> map) throws MonitorException {
    assert Thread.holdsLock(this);

    int used = prologue.getUsed();
    long modificationTime = prologue.getModificationTimeStamp();

    if ((used > lastUsed) || (lastModificationTime > modificationTime)) {

      lastUsed = used;
      lastModificationTime = modificationTime;

      Monitor monitor = getNextMonitorEntry();
      while (monitor != null) {
        String name = monitor.getName();

        // guard against duplicate entries
        if (!map.containsKey(name)) {
          map.put(name, monitor);

          /*
           * insertedMonitors is null when called from pollFor()
           * via buildMonitorMap(). Since we update insertedMonitors
           * at the end of buildMonitorMap(), it's ok to skip the
           * add here.
           */
          if (insertedMonitors != null) {
            insertedMonitors.add(monitor);
          }
        }
        monitor = getNextMonitorEntry();
      }
    }
  }
  /**
   * Method to poll the instrumentation memory for a counter with the given name. The polling period
   * is bounded by the timeLimit argument.
   */
  protected Monitor pollFor(Map<String, Monitor> map, String name, long timeLimit)
      throws MonitorException {
    Monitor monitor = null;

    log("polling for: " + lvmid + "," + name + " ");

    pollForEntry = nextEntry;
    while ((monitor = map.get(name)) == null) {
      log(".");

      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {
      }

      long t = System.currentTimeMillis();
      if ((t > timeLimit) || (overflow.intValue() > 0)) {
        lognl("failed: " + lvmid + "," + name);
        dumpAll(map, lvmid);
        throw new MonitorException("Could not find expected counter");
      }

      getNewMonitors(map);
    }
    lognl("success: " + lvmid + "," + name);
    return monitor;
  }
  /**
   * Method to provide a gross level of synchronization with the target monitored jvm.
   *
   * <p>gross synchronization works by polling for the hotspot.rt.hrt.ticks counter, which is the
   * last counter created by the StatSampler initialization code. The counter is updated when the
   * watcher thread starts scheduling tasks, which is the last thing done in vm initialization.
   */
  protected void synchWithTarget(Map<String, Monitor> map) throws MonitorException {
    /*
     * synch must happen with syncWaitMs from now. Default is 5 seconds,
     * which is reasonabally generous and should provide for extreme
     * situations like startup delays due to allocation of large ISM heaps.
     */
    long timeLimit = System.currentTimeMillis() + syncWaitMs;

    String name = "hotspot.rt.hrt.ticks";
    LongMonitor ticks = (LongMonitor) pollFor(map, name, timeLimit);

    /*
     * loop waiting for the ticks counter to be non zero. This is
     * an indication that the jvm is initialized.
     */
    log("synchWithTarget: " + lvmid + " ");
    while (ticks.longValue() == 0) {
      log(".");

      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {
      }

      if (System.currentTimeMillis() > timeLimit) {
        lognl("failed: " + lvmid);
        throw new MonitorException("Could Not Synchronize with target");
      }
    }
    lognl("success: " + lvmid);
  }
  /** {@inheritDoc} */
  protected MonitorStatus getMonitorStatus(Map<String, Monitor> map) throws MonitorException {
    assert Thread.holdsLock(this);
    assert insertedMonitors != null;

    // load any new monitors
    getNewMonitors(map);

    // current implementation doesn't support deletion or reuse of entries
    ArrayList removed = EMPTY_LIST;
    ArrayList inserted = insertedMonitors;

    insertedMonitors = new ArrayList<Monitor>();
    return new MonitorStatus(inserted, removed);
  }
  /** {@inheritDoc} */
  protected void buildMonitorMap(Map<String, Monitor> map) throws MonitorException {
    assert Thread.holdsLock(this);

    // start at the beginning of the buffer
    buffer.rewind();

    // create pseudo monitors
    buildPseudoMonitors(map);

    // position buffer to start of the data section
    buffer.position(prologue.getSize());
    nextEntry = buffer.position();
    perfDataItem = 0;

    int used = prologue.getUsed();
    long modificationTime = prologue.getModificationTimeStamp();

    Monitor m = getNextMonitorEntry();
    while (m != null) {
      map.put(m.getName(), m);
      m = getNextMonitorEntry();
    }

    /*
     * set the last modification data. These are set to the values
     * recorded before parsing the data structure. This allows the
     * the data structure to be modified while the Map is being built.
     * The Map may contain more entries than indicated based on the
     * time stamp, but this is handled by ignoring duplicate entries
     * when the Map is updated in getNewMonitors().
     */
    lastUsed = used;
    lastModificationTime = modificationTime;

    // synchronize with the target jvm
    synchWithTarget(map);

    // work around 1.4.2 counter inititization bugs
    kludge(map);

    insertedMonitors = new ArrayList<Monitor>(map.values());
  }