public void run()

in core/src/main/java/hudson/model/Executor.java [320:463]


    public void run() {
        if (!owner.isOnline()) {
            resetWorkUnit("went off-line before the task's worker thread started");
            owner.removeExecutor(this);
            queue.scheduleMaintenance();
            return;
        }
        if (owner.getNode() == null) {
            resetWorkUnit("was removed before the task's worker thread started");
            owner.removeExecutor(this);
            queue.scheduleMaintenance();
            return;
        }
        final WorkUnit workUnit;
        lock.writeLock().lock();
        try {
            startTime = System.currentTimeMillis();
            workUnit = this.workUnit;
        } finally {
            lock.writeLock().unlock();
        }

        try (ACLContext ctx = ACL.as(ACL.SYSTEM)) {
            SubTask task;
            // transition from idle to building.
            // perform this state change as an atomic operation wrt other queue operations
            task = Queue.withLock(new java.util.concurrent.Callable<SubTask>() {
                @Override
                public SubTask call() throws Exception {
                    if (!owner.isOnline()) {
                        resetWorkUnit("went off-line before the task's worker thread was ready to execute");
                        return null;
                    }
                    if (owner.getNode() == null) {
                        resetWorkUnit("was removed before the task's worker thread was ready to execute");
                        return null;
                    }
                    // after this point we cannot unwind the assignment of the work unit, if the owner
                    // is removed or goes off-line then the build will just have to fail.
                    workUnit.setExecutor(Executor.this);
                    queue.onStartExecuting(Executor.this);
                    if (LOGGER.isLoggable(FINE))
                        LOGGER.log(FINE, getName()+" grabbed "+workUnit+" from queue");
                    SubTask task = workUnit.work;
                    Executable executable = task.createExecutable();
                    if (executable == null) {
                        String displayName = task instanceof Queue.Task ? ((Queue.Task) task).getFullDisplayName() : task.getDisplayName();
                        LOGGER.log(WARNING, "{0} cannot be run (for example because it is disabled)", displayName);
                    }
                    lock.writeLock().lock();
                    try {
                        Executor.this.executable = executable;
                    } finally {
                        lock.writeLock().unlock();
                    }
                    workUnit.setExecutable(executable);
                    return task;
                }
            });
            Executable executable;
            lock.readLock().lock();
            try {
                if (this.workUnit == null) {
                    // we called resetWorkUnit, so bail. Outer finally will remove this and schedule queue maintenance
                    return;
                }
                executable = this.executable;
            } finally {
                lock.readLock().unlock();
            }
            if (LOGGER.isLoggable(FINE))
                LOGGER.log(FINE, getName()+" is going to execute "+executable);

            Throwable problems = null;
            try {
                workUnit.context.synchronizeStart();

                // this code handles the behavior of null Executables returned
                // by tasks. In such case Jenkins starts the workUnit in order
                // to report results to console outputs.
                if (executable == null) {
                    return;
                }

                executableEstimatedDuration = executable.getEstimatedDuration();

                if (executable instanceof Actionable) {
                    if (LOGGER.isLoggable(Level.FINER)) {
                        LOGGER.log(FINER, "when running {0} from {1} we are copying {2} actions whereas the item currently has {3}", new Object[] {executable, workUnit.context.item, workUnit.context.actions, workUnit.context.item.getAllActions()});
                    }
                    for (Action action: workUnit.context.actions) {
                        ((Actionable) executable).addAction(action);
                    }
                }

                setName(getName() + " : executing " + executable.toString());
                Authentication auth = workUnit.context.item.authenticate();
                LOGGER.log(FINE, "{0} is now executing {1} as {2}", new Object[] {getName(), executable, auth});
                if (LOGGER.isLoggable(FINE) && auth.equals(ACL.SYSTEM)) { // i.e., unspecified
                    if (QueueItemAuthenticatorDescriptor.all().isEmpty()) {
                        LOGGER.fine("no QueueItemAuthenticator implementations installed");
                    } else if (QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
                        LOGGER.fine("no QueueItemAuthenticator implementations configured");
                    } else {
                        LOGGER.log(FINE, "some QueueItemAuthenticator implementations configured but neglected to authenticate {0}", executable);
                    }
                }
                try (ACLContext context = ACL.as(auth)) {
                    queue.execute(executable, task);
                }
            } catch (AsynchronousExecution x) {
                lock.writeLock().lock();
                try {
                    x.setExecutorWithoutCompleting(this);
                    this.asynchronousExecution = x;
                } finally {
                    lock.writeLock().unlock();
                }
                x.maybeComplete();
            } catch (Throwable e) {
                problems = e;
            } finally {
                boolean needFinish1;
                lock.readLock().lock();
                try {
                    needFinish1 = asynchronousExecution == null;
                } finally {
                    lock.readLock().unlock();
                }
                if (needFinish1) {
                    finish1(problems);
                }
            }
        } catch (InterruptedException e) {
            LOGGER.log(FINE, getName()+" interrupted",e);
            // die peacefully
        } catch(Exception | Error e) {
            LOGGER.log(SEVERE, getName()+": Unexpected executor death", e);
        } finally {
            if (asynchronousExecution == null) {
                finish2();
            }
        }
    }