Beispiel #1
0
  /**
   * Called by the executor to fetch something to build next.
   *
   * <p>This method blocks until a next project becomes buildable.
   */
  public Queue.Item pop() throws InterruptedException {
    final Executor exec = Executor.currentExecutor();

    try {
      while (true) {
        final JobOffer offer = new JobOffer(exec);
        long sleep = -1;

        synchronized (this) {
          // consider myself parked
          assert !parked.containsKey(exec);
          parked.put(exec, offer);

          // reuse executor thread to do a queue maintenance.
          // at the end of this we get all the buildable jobs
          // in the buildables field.
          maintain();

          // allocate buildable jobs to executors
          Iterator<BuildableItem> itr = buildables.iterator();
          while (itr.hasNext()) {
            BuildableItem p = itr.next();

            // one last check to make sure this build is not blocked.
            if (isBuildBlocked(p.task)) {
              itr.remove();
              blockedProjects.put(p.task, new BlockedItem(p));
              continue;
            }

            JobOffer runner = loadBalancer.choose(p.task, new ApplicableJobOfferList(p.task));
            if (runner == null)
              // if we couldn't find the executor that fits,
              // just leave it in the buildables list and
              // check if we can execute other projects
              continue;

            assert runner.canTake(p.task);

            // found a matching executor. use it.
            runner.set(p);
            itr.remove();
          }

          // we went over all the buildable projects and awaken
          // all the executors that got work to do. now, go to sleep
          // until this thread is awakened. If this executor assigned a job to
          // itself above, the block method will return immediately.

          if (!waitingList.isEmpty()) {
            // wait until the first item in the queue is due
            sleep = peek().timestamp.getTimeInMillis() - new GregorianCalendar().getTimeInMillis();
            if (sleep < 100) sleep = 100; // avoid wait(0)
          }
        }

        // this needs to be done outside synchronized block,
        // so that executors can maintain a queue while others are sleeping
        if (sleep == -1) offer.event.block();
        else offer.event.block(sleep);

        synchronized (this) {
          // retract the offer object
          assert parked.get(exec) == offer;
          parked.remove(exec);

          // am I woken up because I have a project to build?
          if (offer.item != null) {
            // if so, just build it
            LOGGER.fine("Pop returning " + offer.item + " for " + exec.getName());
            offer.item.future.startExecuting(exec);
            return offer.item;
          }
          // otherwise run a queue maintenance
        }
      }
    } finally {
      synchronized (this) {
        // remove myself from the parked list
        JobOffer offer = parked.remove(exec);
        if (offer != null && offer.item != null) {
          // we are already assigned a project,
          // ask for someone else to build it.
          // note that while this thread is waiting for CPU
          // someone else can schedule this build again,
          // so check the contains method first.
          if (!contains(offer.item.task)) buildables.put(offer.item.task, offer.item);
        }

        // since this executor might have been chosen for
        // maintenance, schedule another one. Worst case
        // we'll just run a pointless maintenance, and that's
        // fine.
        scheduleMaintenance();
      }
    }
  }
Beispiel #2
0
 protected void doRun() {
   Queue q = queue.get();
   if (q != null) q.maintain();
   else cancel();
 }