private ProBInstance startProlog() {
    ProcessHandle processTuple = processProvider.get();
    Process process = processTuple.getProcess();
    String key = processTuple.getKey();
    final BufferedReader stream =
        new BufferedReader(
            new InputStreamReader(process.getInputStream(), Charset.defaultCharset()));

    Map<Class<? extends AbstractCliPattern<?>>, AbstractCliPattern<?>> cliInformation =
        extractCliInformation(stream);

    Integer port = ((PortPattern) cliInformation.get(PortPattern.class)).getValue();
    Long userInterruptReference =
        ((InterruptRefPattern) cliInformation.get(InterruptRefPattern.class)).getValue();

    ProBConnection connection = new ProBConnection(key, port);

    try {
      processCounter.incrementAndGet();
      connection.connect();
      ProBInstance cli =
          new ProBInstance(
              process, stream, userInterruptReference, connection, home, osInfo, processCounter);
      processes.add(new WeakReference<ProBInstance>(cli));
      return cli;
    } catch (IOException e) {
      processCounter.decrementAndGet();
      logger.error("Error connecting to Prolog binary.", e);
      return null;
    }
  }
Exemple #2
0
 /** Test (Not really a test) that dumps the list of all Processes. */
 @Test
 public static void test4() {
   printf("    Parent     Child  Info%n");
   Stream<ProcessHandle> s = ProcessHandle.allProcesses();
   ProcessHandle[] processes = s.toArray(ProcessHandle[]::new);
   int len = processes.length;
   ProcessHandle[] parent = new ProcessHandle[len];
   Set<ProcessHandle> processesSet = Arrays.stream(processes).collect(Collectors.toSet());
   Integer[] sortindex = new Integer[len];
   for (int i = 0; i < len; i++) {
     sortindex[i] = i;
   }
   for (int i = 0; i < len; i++) {
     parent[sortindex[i]] = processes[sortindex[i]].parent().orElse(null);
   }
   Arrays.sort(
       sortindex,
       (i1, i2) -> {
         int cmp =
             Long.compare(
                 (parent[i1] == null ? 0L : parent[i1].getPid()),
                 (parent[i2] == null ? 0L : parent[i2].getPid()));
         if (cmp == 0) {
           cmp =
               Long.compare(
                   (processes[i1] == null ? 0L : processes[i1].getPid()),
                   (processes[i2] == null ? 0L : processes[i2].getPid()));
         }
         return cmp;
       });
   boolean fail = false;
   for (int i = 0; i < len; i++) {
     ProcessHandle p = processes[sortindex[i]];
     ProcessHandle p_parent = parent[sortindex[i]];
     ProcessHandle.Info info = p.info();
     String indent = "    ";
     if (p_parent != null) {
       if (!processesSet.contains(p_parent)) {
         fail = true;
         indent = "*** ";
       }
     }
     printf("%s %7s, %7s, %s%n", indent, p_parent, p, info);
   }
   Assert.assertFalse(fail, "Parents missing from all Processes");
 }
Exemple #3
0
  /** Test counting and spawning and counting of Processes. */
  @Test
  public static void test1() {
    final int MAXCHILDREN = 2;
    List<JavaChild> spawned = new ArrayList<>();

    try {
      ProcessHandle self = ProcessHandle.current();

      printf("self pid: %d%n", self.getPid());
      printDeep(self, "");

      for (int i = 0; i < MAXCHILDREN; i++) {
        // spawn and wait for instructions
        spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
      }

      // Verify spawned Process is in list of children
      final List<ProcessHandle> initialChildren = getChildren(self);
      spawned
          .stream()
          .map(Process::toHandle)
          .filter(p -> !initialChildren.contains(p))
          .forEach(p -> Assert.fail("Spawned process missing from children: " + p));

      // Send exit command to each spawned Process
      spawned.forEach(
          p -> {
            try {
              p.sendAction("exit", "");
            } catch (IOException ex) {
              Assert.fail("IOException in sendAction", ex);
            }
          });

      // Wait for each Process to exit
      spawned.forEach(
          p -> {
            do {
              try {
                Assert.assertEquals(p.waitFor(), 0, "exit status incorrect");
                break;
              } catch (InterruptedException ex) {
                continue; // Retry
              }
            } while (true);
          });

      // Verify that ProcessHandle.isAlive sees each of them as not alive
      for (Process p : spawned) {
        ProcessHandle ph = p.toHandle();
        Assert.assertFalse(ph.isAlive(), "ProcessHandle.isAlive for exited process: " + ph);
      }

      // Verify spawned processes are not visible as children
      final List<ProcessHandle> afterChildren = getChildren(self);
      spawned
          .stream()
          .map(Process::toHandle)
          .filter(p -> afterChildren.contains(p))
          .forEach(p -> Assert.fail("Spawned process missing from children: " + p));

    } catch (IOException ioe) {
      Assert.fail("unable to spawn process", ioe);
    } finally {
      // Cleanup any left over processes
      spawned
          .stream()
          .map(Process::toHandle)
          .filter(ProcessHandle::isAlive)
          .forEach(
              ph -> {
                printDeep(ph, "test1 cleanup: ");
                ph.destroyForcibly();
              });
    }
  }
Exemple #4
0
  /** A test for scale; launch a large number (14) of subprocesses. */
  @Test
  public static void test5() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    int factor = 2;
    JavaChild p1 = null;
    Instant start = Instant.now();
    try {
      p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();

      printf("Spawning %d x %d x %d processes, pid: %d%n", factor, factor, factor, p1.getPid());

      // Start the first tier of subprocesses
      p1.sendAction("spawn", factor, "stdin");

      // Start the second tier of subprocesses
      p1.sendAction("child", "spawn", factor, "stdin");

      // Start the third tier of subprocesses
      p1.sendAction("child", "child", "spawn", factor, "stdin");

      int newChildren = factor * (1 + factor * (1 + factor));
      CountDownLatch spawnCount = new CountDownLatch(newChildren);

      // Gather the PIDs from the output of the spawning process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      Assert.assertEquals(getChildren(p1Handle).size(), factor, "expected direct children");
      count = getDescendants(p1Handle).size();
      long totalChildren = factor * factor * factor + factor * factor + factor;
      Assert.assertTrue(
          count >= totalChildren, "expected at least " + totalChildren + ", actual: " + count);

      List<ProcessHandle> subprocesses = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          subprocesses.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      p1.getOutputStream().close(); // Close stdin for the controlling p1
      p1.waitFor();
    } catch (InterruptedException | IOException ex) {
      Assert.fail("Unexpected Exception", ex);
    } finally {
      printf("Duration: %s%n", Duration.between(start, Instant.now()));
      if (p1 != null) {
        p1.destroyForcibly();
      }
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p, "Process Cleanup: ");
              p.destroyForcibly();
            }
          });
    }
  }
Exemple #5
0
  /**
   * Test destroy of processes. A JavaChild is started and it starts three children. Each one is
   * then checked to be alive and listed by descendants and forcibly destroyed. After they exit they
   * should no longer be listed by descendants.
   */
  @Test
  public static void test3() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    try {
      ProcessHandle self = ProcessHandle.current();

      JavaChild p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();
      printf(" p1: %s%n", p1.getPid());

      int newChildren = 3;
      CountDownLatch spawnCount = new CountDownLatch(newChildren);
      // Spawn children and have them wait
      p1.sendAction("spawn", newChildren, "stdin");

      // Gather the PIDs from the output of the spawning process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      // Verify that all spawned children are alive, show up in the descendants list
      // then destroy them
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
            p.destroyForcibly();
          });
      Assert.assertEquals(processes.size(), newChildren, "Wrong number of children");

      // Wait for each of the processes to exit
      processes.forEach(
          (p, parent) -> {
            for (long retries = Utils.adjustTimeout(100L); retries > 0; retries--) {
              if (!p.isAlive()) {
                return; // not alive, go on to the next
              }
              // Wait a bit and retry
              try {
                Thread.sleep(100L);
              } catch (InterruptedException ie) {
                // try again
              }
            }
            printf(
                "Timeout waiting for exit of pid %s, parent: %s, info: %s%n", p, parent, p.info());
            Assert.fail("Process still alive: " + p);
          });
      p1.destroyForcibly();
      p1.waitFor();

      // Verify that none of the spawned children are still listed by descendants
      List<ProcessHandle> remaining = getDescendants(self);
      Assert.assertFalse(remaining.remove(p1Handle), "Child p1 should have exited");
      remaining = remaining.stream().filter(processes::containsKey).collect(Collectors.toList());
      Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining);

    } catch (IOException ioe) {
      Assert.fail("Spawn of subprocess failed", ioe);
    } catch (InterruptedException inte) {
      Assert.fail("InterruptedException", inte);
    } finally {
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p);
              p.destroyForcibly();
            }
          });
    }
  }
Exemple #6
0
  /** Test counting and spawning and counting of Processes. */
  @Test
  public static void test2() {
    try {
      ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

      ProcessHandle self = ProcessHandle.current();
      List<ProcessHandle> initialChildren = getChildren(self);
      long count = initialChildren.size();
      if (count > 0) {
        initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
      }

      JavaChild p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();
      printf("  p1 pid: %d%n", p1.getPid());

      // Gather the PIDs from the output of the spawing process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
            }
          });

      int spawnNew = 3;
      p1.sendAction("spawn", spawnNew, "stdin");

      // Wait for direct children to be created and save the list
      List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, spawnNew);
      Optional<Instant> p1Start = p1Handle.info().startInstant();
      for (ProcessHandle ph : subprocesses) {
        Assert.assertTrue(ph.isAlive(), "Child should be alive: " + ph);
        // Verify each child was started after the parent
        ph.info()
            .startInstant()
            .ifPresent(
                childStart ->
                    p1Start.ifPresent(
                        parentStart -> {
                          Assert.assertFalse(
                              childStart.isBefore(parentStart),
                              String.format(
                                  "Child process started before parent: child: %s, parent: %s",
                                  childStart, parentStart));
                        }));
      }

      // Each child spawns two processes and waits for commands
      int spawnNewSub = 2;
      p1.sendAction("child", "spawn", spawnNewSub, "stdin");

      // Poll until all 9 child processes exist or the timeout is reached
      int expected = 9;
      long timeout = Utils.adjustTimeout(60L);
      Instant endTimeout = Instant.now().plusSeconds(timeout);
      do {
        Thread.sleep(200L);
        printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
      } while (processes.size() < expected && Instant.now().isBefore(endTimeout));

      if (processes.size() < expected) {
        printf("WARNING: not all children have been started. Can't complete test.%n");
        printf("         You can try to increase the timeout or%n");
        printf("         you can try to use a faster VM (i.e. not a debug version).%n");
      }

      // show the complete list of children (for debug)
      List<ProcessHandle> descendants = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          descendants.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      // Verify that all spawned children show up in the descendants  List
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
          });

      // Closing JavaChild's InputStream will cause all children to exit
      p1.getOutputStream().close();

      for (ProcessHandle p : descendants) {
        try {
          p.onExit().get(); // wait for the child to exit
        } catch (ExecutionException e) {
          Assert.fail("waiting for process to exit", e);
        }
      }
      p1.waitFor(); // wait for spawned process to exit

      // Verify spawned processes are no longer alive
      processes.forEach(
          (ph, parent) -> Assert.assertFalse(ph.isAlive(), "process should not be alive: " + ph));
    } catch (IOException | InterruptedException t) {
      t.printStackTrace();
      throw new RuntimeException(t);
    }
  }