public ResolveTask getOrCreateTaskResolving(
     final ValueRequirement valueRequirement,
     final ResolveTask parentTask,
     final Collection<FunctionExclusionGroup> functionExclusion) {
   final ResolveTask newTask = new ResolveTask(valueRequirement, parentTask, functionExclusion);
   do {
     ResolveTask task;
     final Map<ResolveTask, ResolveTask> tasks = getBuilder().getOrCreateTasks(valueRequirement);
     synchronized (tasks) {
       if (tasks.containsKey(null)) {
         // The cache has been flushed
         continue;
       }
       task = tasks.get(newTask);
       if (task == null) {
         newTask.addRef(); // Already got a reference, increment for the collection
         tasks.put(newTask, newTask);
       } else {
         task.addRef(); // Got the task lock, increment so we can return it
       }
     }
     if (task != null) {
       s_logger.debug("Using existing task {}", task);
       newTask.release(this); // Discard local allocation
       return task;
     } else {
       getBuilder().incrementActiveResolveTasks();
       // Don't call run; we want to fork this out to a new worker thread, never call inline
       newTask.addRef(); // Reference held by the run queue
       submit(newTask);
       return newTask;
     }
   } while (true);
 }
 public void discardTask(final ResolveTask task) {
   // TODO: Could we post "discardTask" tasks to a queue and have them done in batches by a
   // ContextRunnable?
   do {
     final Map<ResolveTask, ResolveTask> tasks = getBuilder().getTasks(task.getValueRequirement());
     if (tasks == null) {
       return;
     }
     synchronized (tasks) {
       if (tasks.containsKey(null)) {
         continue;
       }
       final int rc = task.getRefCount();
       if (rc == 0) {
         // Not referenced by us by definition
         return;
       }
       if (rc != 1) {
         if (!task.isFinished()) {
           // Can't discard this -- something might be waiting on a result from it??
           return;
         }
       }
       final ResolveTask removed = tasks.remove(task);
       if (removed == null) {
         // Task has already been discarded
         return;
       }
       if (removed != task) {
         // Task has already been discarded and replaced by an equivalent; don't discard that
         tasks.put(removed, removed);
         return;
       }
     }
     task.release(this);
     getBuilder().decrementActiveResolveTasks();
   } while (true);
 }
 public ResolvedValueProducer resolveRequirement(
     final ValueRequirement rawRequirement,
     final ResolveTask dependent,
     final Collection<FunctionExclusionGroup> functionExclusion) {
   final ValueRequirement requirement = simplifyType(rawRequirement);
   s_logger.debug("Resolve requirement {}", requirement);
   if ((dependent != null) && dependent.hasParent(requirement)) {
     s_logger.debug("Can't introduce a ValueRequirement loop");
     return null;
   }
   RequirementResolver resolver = null;
   final ResolveTask[] tasks = getTasksResolving(requirement);
   if (tasks != null) {
     int i = 0;
     int l = tasks.length;
     while (i < l) {
       final ResolveTask task = tasks[i];
       if ((dependent == null) || !dependent.hasParent(task)) {
         if ((task.isFinished() && !task.wasRecursionDetected())
             || (ObjectUtils.equals(functionExclusion, task.getFunctionExclusion())
                 && task.hasParentValueRequirements(dependent))) {
           // The task we've found has either already completed, without hitting a recursion
           // constraint. Or
           // the task is identical to the fallback task we'd create naturally. In either case,
           // release everything
           // else and use it.
           for (int j = 0; j < i; j++) {
             tasks[j].release(this);
           }
           for (int j = i + 1; j < l; j++) {
             tasks[j].release(this);
           }
           return task;
         }
         i++;
       } else {
         task.release(this);
         tasks[i] = tasks[--l];
       }
     }
     // Anything left in the array is suitable for use in a RequirementResolver
     if (l > 0) {
       resolver = new RequirementResolver(requirement, dependent, functionExclusion);
       if (l != tasks.length) {
         resolver.setTasks(this, Arrays.copyOf(tasks, l));
       } else {
         resolver.setTasks(this, tasks);
       }
       for (i = 0; i < l; i++) {
         tasks[i].release(this);
       }
     }
   }
   if (resolver != null) {
     resolver.start(this);
     return resolver;
   } else {
     s_logger.debug("Using direct resolution {}/{}", requirement, dependent);
     return getOrCreateTaskResolving(requirement, dependent, functionExclusion);
   }
 }