/hudson-core/src/main/java/hudson/model/queue/WorkUnitContext.java

http://github.com/hudson/hudson · Java · 176 lines · 89 code · 25 blank · 62 comment · 10 complexity · e946382d07b2fdc44e18e10c79abfab6 MD5 · raw file

  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2010, InfraDNA, Inc.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package hudson.model.queue;
  25. import hudson.model.Action;
  26. import hudson.model.Executor;
  27. import hudson.model.Queue;
  28. import hudson.model.Queue.BuildableItem;
  29. import hudson.model.Queue.Task;
  30. import java.util.ArrayList;
  31. import java.util.Collections;
  32. import java.util.List;
  33. /**
  34. * Holds the information shared between {@link WorkUnit}s created from the same {@link Task}.
  35. *
  36. * @author Kohsuke Kawaguchi
  37. */
  38. public final class WorkUnitContext {
  39. //TODO: review and check whether we can do it private
  40. public final BuildableItem item;
  41. //TODO: review and check whether we can do it private
  42. public final Task task;
  43. /**
  44. * Once the execution is complete, update this future object with the outcome.
  45. */
  46. //TODO: review and check whether we can do it private
  47. public final FutureImpl future;
  48. /**
  49. * Associated parameters to the build.
  50. */
  51. //TODO: review and check whether we can do it private
  52. public final List<Action> actions;
  53. private final Latch startLatch, endLatch;
  54. private List<WorkUnit> workUnits = new ArrayList<WorkUnit>();
  55. /**
  56. * If the execution is aborted, set to non-null that indicates where it was aborted.
  57. */
  58. private volatile Throwable aborted;
  59. public WorkUnitContext(BuildableItem item) {
  60. this.item = item;
  61. this.task = item.task;
  62. this.future = (FutureImpl)item.getFuture();
  63. this.actions = item.getActions();
  64. // +1 for the main task
  65. int workUnitSize = Tasks.getSubTasksOf(task).size();
  66. startLatch = new Latch(workUnitSize) {
  67. @Override
  68. protected void onCriteriaMet() {
  69. // on behalf of the member Executors,
  70. // the one that executes the main thing will send notifications
  71. Executor e = Executor.currentExecutor();
  72. if (e.getCurrentWorkUnit().isMainWork()) {
  73. e.getOwner().taskAccepted(e,task);
  74. }
  75. }
  76. };
  77. endLatch = new Latch(workUnitSize);
  78. }
  79. public BuildableItem getItem() {
  80. return item;
  81. }
  82. public Task getTask() {
  83. return task;
  84. }
  85. public FutureImpl getFuture() {
  86. return future;
  87. }
  88. public List<Action> getActions() {
  89. return actions;
  90. }
  91. /**
  92. * Called by the executor that executes a member {@link SubTask} that belongs to this task
  93. * to create its {@link WorkUnit}.
  94. */
  95. public WorkUnit createWorkUnit(SubTask execUnit) {
  96. future.addExecutor(Executor.currentExecutor());
  97. WorkUnit wu = new WorkUnit(this, execUnit);
  98. workUnits.add(wu);
  99. return wu;
  100. }
  101. public List<WorkUnit> getWorkUnits() {
  102. return Collections.unmodifiableList(workUnits);
  103. }
  104. public WorkUnit getPrimaryWorkUnit() {
  105. return workUnits.get(0);
  106. }
  107. /**
  108. * All the {@link Executor}s that jointly execute a {@link Task} call this method to synchronize on the start.
  109. */
  110. public void synchronizeStart() throws InterruptedException {
  111. startLatch.synchronize();
  112. }
  113. /**
  114. * All the {@link Executor}s that jointly execute a {@link Task} call this method to synchronize on the end of the task.
  115. *
  116. * @throws InterruptedException
  117. * If any of the member thread is interrupted while waiting for other threads to join, all
  118. * the member threads will report {@link InterruptedException}.
  119. */
  120. public void synchronizeEnd(Queue.Executable executable, Throwable problems, long duration) throws InterruptedException {
  121. endLatch.synchronize();
  122. // the main thread will send a notification
  123. Executor e = Executor.currentExecutor();
  124. WorkUnit wu = e.getCurrentWorkUnit();
  125. if (wu.isMainWork()) {
  126. if (problems == null) {
  127. future.set(executable);
  128. e.getOwner().taskCompleted(e, task, duration);
  129. } else {
  130. future.set(problems);
  131. e.getOwner().taskCompletedWithProblems(e, task, duration, problems);
  132. }
  133. }
  134. }
  135. /**
  136. * When one of the work unit is aborted, call this method to abort all the other work units.
  137. */
  138. public synchronized void abort(Throwable cause) {
  139. if (cause==null) throw new IllegalArgumentException();
  140. if (aborted!=null) return; // already aborted
  141. aborted = cause;
  142. startLatch.abort(cause);
  143. endLatch.abort(cause);
  144. Thread c = Thread.currentThread();
  145. for (WorkUnit wu : workUnits) {
  146. Executor e = wu.getExecutor();
  147. if (e!=null && e!=c)
  148. e.interrupt();
  149. }
  150. }
  151. }