private void doStart() {
   if (!started.get()) {
     try {
       dataRecorderDriver.start();
     } finally {
       try {
         strictExecutor.start();
       } finally {
         try {
           dsPacketExecutor.start();
         } finally {
           started.set(true);
         }
       }
     }
   }
 }
 private void doRestart() {
   if (started.get()) {
     // Kill any remaining commands ...
     scheduler.killAll();
   } else {
     try {
       dataRecorderDriver.start();
     } finally {
       try {
         strictExecutor.start();
       } finally {
         try {
           dsPacketExecutor.start();
         } finally {
           started.set(true);
         }
       }
     }
   }
 }
 private void doShutdown() {
   try {
     // First stop executing immediately; at this point, no Executables
     // will run ...
     strictExecutor.stop();
   } finally {
     try {
       dsPacketExecutor.stop();
     } finally {
       try {
         // Kill any remaining commands ...
         scheduler.killAll();
       } finally {
         try {
           // Finally flush the data recorder ...
           dataRecorderDriver.stop();
         } finally {
           started.set(false);
         }
       }
     }
   }
 }
  private Strongback(Configurator config, Strongback previousInstance) {
    boolean start = false;
    if (previousInstance != null) {
      start = previousInstance.started.get();
      // Terminates all currently-scheduled commands and stops the executor's thread (if running)
      // ...
      previousInstance.doShutdown();
      strictExecutables = previousInstance.strictExecutables;
      executables = previousInstance.executables;
      switchReactor = previousInstance.switchReactor;

      executables.unregister(previousInstance.dataRecorderDriver);
      executables.unregister(previousInstance.eventRecorder);
      executables.unregister(previousInstance.scheduler);
      dataRecorderChannels = previousInstance.dataRecorderChannels;
      excessiveExecutionHandler = previousInstance.excessiveExecutionHandler;
    } else {
      executables = new Executables();
      strictExecutables = new Executables();
      switchReactor = new AsyncSwitchReactor();
      executables.register(switchReactor);
      dataRecorderChannels = new DataRecorderChannels();
      excessiveExecutionHandler = config.excessiveExecutorDelayHandler;
    }
    loggers = config.loggersSupplier.get();
    clock = config.timeSystemSupplier.get();
    // Create a new executor ...
    strictExecutor =
        PeriodicExecutor.roboRIONotifierWithFallback(
            "strictExecutor",
            config.executionPeriodInMilliseconds,
            TimeUnit.MILLISECONDS,
            strictExecutables,
            clock,
            loggers.apply("strictExecutor"),
            monitorDelay("strictExecutor", 100, TimeUnit.MILLISECONDS));

    dsPacketExecutor =
        PeriodicExecutor.waitForDSPacketWithFallback(
            "dsPacketExecutor",
            config.driverstationExecutorTimeoutInMilliseconds,
            TimeUnit.MILLISECONDS,
            executables,
            clock,
            loggers.apply("dsPacketExecutor"),
            monitorDelay("dsPacketExecutor", 100, TimeUnit.MILLISECONDS));

    // Create a new event recorder ...
    if (config.eventWriterFactory != null) {
      eventRecorder = new AsyncEventRecorder(config.eventWriterFactory.get(), clock);
      executables.register(eventRecorder);
    } else {
      eventRecorder = EventRecorder.noOp();
    }

    // Create a new scheduler that optionally records command state
    // transitions. Note that we ignore everything in
    // the previous instance's scheduler, since all commands would have been
    // terminated (as intended) ...
    CommandListener commandListener =
        config.recordCommandStateChanges ? this::recordCommand : this::recordNoCommands;
    scheduler = new Scheduler(loggers.apply("scheduler"), commandListener);
    executables.register(scheduler);

    // Create a new data recorder driver ...
    dataRecorderDriver = new DataRecorderDriver(dataRecorderChannels, config.dataWriterFactory);
    executables.register(dataRecorderDriver);

    // Start this if the previous was already started ...
    if (previousInstance != null && start) {

      doStart();
    }
  }