Issues capturing process IDs Java - java

I recently asked a question that helped me understand what a C program is doing in terms of Java. My goal is now to perform a C-like fork of two new child processes, while keeping track of parent process IDs and child process Ids. I am unsure, however, if this is possible.
Here, I've attempted to initiate process P and run two child processes (which I believed to be the InputStreamReaders isr and wasr ). I've gotten the PID of process P. But, where I'm stuck is the fact that InputStreamReader is not really a process, so I can't get the process ID.
I'll mention like I did in the other post that this is a homework assignment which provides C code instruction but urging Java code responses. The end goal is to be able to print "Child process ID of Parent process ID has begun" and "Child process ID has terminated" -- this is why it's important that I keep track of everyone's ID.
I found this other post, but I'm not sure how to adapt it.
UPDATE : With help of another SO user, I've realized that i may be approaching the problem in the wrong way. Here, parent process is the java process and child process is the native process. Updated code below.
Original Code
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class processesorigin {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec("/bin/ls");
final InputStream is = p.getInputStream();
final InputStream was = p.getInputStream();
Thread t = new Thread(new Runnable() {
public void run() {
InputStreamReader isr = new InputStreamReader(is);
InputStreamReader wasr = new InputStreamReader(was);
int ch;
try {
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
while ((ch = wasr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
p.waitFor();
t.join();
int pid = 0;
if(p.getClass().getName().equals("java.lang.UNIXProcess")) {
try {
Field f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
pid = f.getInt(p);
}
catch (Throwable e) {
}
}
System.out.println("Process " + pid + " terminates.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
UPDATED CODE Using these tips and another SO user, I have found how to capture the Java process ID. There is however, still an issue with signaling of the start of each process. This might be another question though.
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import sun.management.VMManagement;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
class processesorigin {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec("/bin/ls");
Process q = Runtime.getRuntime().exec("/bin/ls");
final InputStream is = p.getInputStream();
final InputStream was = q.getInputStream();
/*get PID of Java process*/
final String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
final String jvmPid = runtimeName.split("#")[0];
int pid = 0;
int qid = 0;
if(p.getClass().getName().equals("java.lang.UNIXProcess")) {
/* get the PID of child processes : native ls command*/
try {
Field f = p.getClass().getDeclaredField("pid");
Field g = q.getClass().getDeclaredField("pid");
f.setAccessible(true);
g.setAccessible(true);
pid = f.getInt(p);
qid = g.getInt(q);
}
catch (Throwable e) {
}
}
final int pidCopy = pid;
final int qidCopy = qid;
Thread t = new Thread(new Runnable() {
public void run() {
InputStreamReader isr = new InputStreamReader(is);
InputStreamReader wasr = new InputStreamReader(was);
int ch;
try {
System.out.print("Child process " + pidCopy + " of Parent process " + jvmPid + " begun.");
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
System.out.print("Child process " + qidCopy + " of Parent process " + jvmPid + " begun.");
while ((ch = wasr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
p.waitFor();
q.waitFor();
t.join();
System.out.println("Child process " + pidCopy + " terminated.");
System.out.println("Child process " + qidCopy + " terminated.");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Regarding your update: The way how you are getting the PID of the native child process should also work on OSX.
Since your assignment is to start two child processes from Java (right?) you can just start two native processes using Runtime.getRuntime().exec(), read and print stdout of each of them, and get and print the PID of each of them.
You can choose to run both processes in the main thread or start each process in a separate thread, basically like it is done in your example.

I am not sure if I fully understand what you want to achieve but maybe this helps you anyway. It is a tiny C program, a kind of wrapper that you can use to start a native process and obtain its PID from Java code:
#include <unistd.h>
#include <stdio.h>
/*
* Purpose of this "program" is to write its PID to stdout so that
* it can be read by a Java program which then can shutdown this
* process gently by sending for example SIGINT to it.
* After printig its PID the process executes the program given
* as argument.
*/
int main(int argc, char *argv[]) {
if(argc < 3) {
fprintf(stderr,"Usage: %s <program> <name> [arg] ...\n", argv[0]);
return -1;
}
/* Write the PID of the process to stdout */
fprintf(stdout,"%i\n", getpid());
/* Flush the buffers */
fflush(NULL);
/*
* Execute the program (specified as file or full path) given as first
* argument in the current process.
*/
return execvp(argv[1], argv + 2);
}
Assuming above code was compiled and the executable copied to /usr/local/bin/jpwrapper, it can be used from Java to run a native process like ls -l /dev, print out the PID when the process started, print its stdout and again the PID when it terminated:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PID {
public static void main(final String[] args) throws Exception {
final Process process = Runtime.getRuntime().exec(new String[] {
"/usr/local/bin/jpwrapper",
"/bin/ls", "ls", "-l", "/dev"});
String pid = null;
try (final BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
// First line of output from the wrapper is the PID
String line = reader.readLine();
pid = line;
System.out.println(String.format(
"Process with PID %s started", pid));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
final int exitCode = process.waitFor();
System.out.println(String.format(
"Process with PID %s terminated with exit code %s",
pid, exitCode));
}
}
But, like I already admitted in my comment, getting the PID from UnixProcess is easier (but also hacky).

Related

How to measure execution time of the code executed by process in Java?

I'm working on a programming online judge project like HackerRank,Codeforces etc...
I have thread pool and when requests comes, the web services gets a thread from thread pool and that thread compiles the code with ProcessBuilder(everything is okey until here), after the compilation, that thread starts execution part by using again a new Processbuilder. But my "time limit exceed" part is not calculated properly. When number of requests is increased, then I think that the process works slowly and for this reason any basic code gets time out. How can I measure the execution time of the code which is executed by a process ?(the measurement should not been affected by number of requests)
EDIT: my process should waitfor user time of the process.But I dont know how to do this.
My execution code is here:
package org.anil.CodeChecker.process;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.concurrent.TimeUnit;
import org.anil.CodeChecker.model.ExecutorModel;
public class Executor {
private ProcessBuilder p;
private String path;
private String input;
private String output;
private String lang;
private long timeInMillis;
public Executor(String path,String input, String output,String lang,long timeInMillis ){
this.path = path;
this.input = input;
this.output = output;
this.lang = lang;
this.timeInMillis = timeInMillis;
}
public ExecutorModel execute(){
ExecutorModel model = new ExecutorModel();
System.out.println("Code started executing");
if(lang.equals("java")){
p = new ProcessBuilder("java","Solution");
}
else if(lang.equals("c")){
p = new ProcessBuilder("./a.out");
}
else if(lang.equals("c++")){
p = new ProcessBuilder("./a.out");
}
else{
System.out.println("language is not correct...");
p = null;
}
p.directory(new File(path));
p.redirectErrorStream(true);
// System.out.println("Current directory "+System.getProperty("user.dir"));
try{
Process pp = p.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(pp.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
/*process e input veriliyor bu kısımda */
OutputStream outputstream = pp.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputstream));
writer.write(input);
writer.flush();
writer.close();
if(!pp.waitFor(timeInMillis, TimeUnit.MILLISECONDS)){
System.out.println("TİME LİMİT EXCEED !!!! ");
model.setTimelimit(true);
return model;
}
else{
model.setTimelimit(false);
int exitCode = pp.exitValue();
System.out.println("Exit Value = "+pp.exitValue());
if(exitCode != 0){
System.out.println("RUNTIME ERROR !!!!!!");
model.setSuccess(false);
model.setRuntimeerror(true);
return model;
}
}
while ( (line = reader.readLine()) != null) {
builder.append(line);
//builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
System.out.println(" output:"+result+" input:"+input);
if(result.charAt(result.length()-1) == ' ')
result = result.substring(0, result.length()-1);
if(result.equals(output)){
model.setSuccess(true);
model.setWronganswer(false);
System.out.println("OUTPUT (SUCCESS) = "+result);
return model;
}
else{
model.setSuccess(false);
model.setWronganswer(true);
System.out.println("OUTPUTTT (FAIL) = "+result);
return model;
}
}catch(IOException ioe){
System.err.println("in execute() "+ioe);
}catch (InterruptedException ex){
System.err.println(ex);
}
System.out.println("CODE EXECUTION FINISHED !");
return model;
}
}
Have you tryed to:
public long getCpuTime() {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
return bean.isCurrentThreadCpuTimeSupported() ? bean.getCurrentThreadCpuTime() : 0L;
}
Using that method as the thread starting a process starts, and then use it again when that thread ends (since it then also ends the process as I understand it), then check delta (aka difference, last usage of the method minus first usage), to get the time how long that thread has been running, thus indirectly getting the time that the process took?
If Im not misstaken, that approach would be better then using for instance System.currentTimeMillis() since it counts the cpu time given to that specific thread, excluding time used by other threads as well as other system processes running in the background.

Execution of Program from Program with Time Constraints (Java)

I'm trying to make program which runs some executable program(call it p), given time limit t ms. It does following tasks:
If program p has executed normally, print it's output to console.
If program p couldn't execute completely within time limit, print "Sorry, needs more time!" and then terminate execution of p.
If program p has terminated abnormally (e.g. RuntimeError), print "Can I've some debugger?"
I'm using ProcessResultReader class in the following program from here. My program is working as long as p finishes it's execution normally or terminate abnormally. But, it doesn't terminate if p itself doesn't terminate after timeout.(Try p with simple while(true) loop with no exit condition). It seems that thread stdout is alive even after execution of stdout.stop(). What am I doing wrong in this code?
Thanks.
import java.util.concurrent.TimeUnit;
import java.io.*;
class ProcessResultReader extends Thread
{
final InputStream is;
final StringBuilder sb;
ProcessResultReader(final InputStream is)
{
this.is = is;
this.sb = new StringBuilder();
}
public void run()
{
try
{
final InputStreamReader isr = new InputStreamReader(is);
final BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
this.sb.append(line).append("\n");
}
}
catch (final IOException ioe)
{
System.err.println(ioe.getMessage());
throw new RuntimeException(ioe);
}
}
#Override
public String toString()
{
return this.sb.toString();
}
public static void main(String[] args) throws Exception
{
int t = 1000;
Process p = Runtime.getRuntime().exec(cmd); //cmd is command to execute program p
ProcessResultReader stdout = new ProcessResultReader(p.getInputStream());
stdout.start();
if(!p.waitFor(t, TimeUnit.MILLISECONDS))
{
stdout.stop();
p.destroy();
System.out.println("Sorry, needs more time!");
}
else
{
if(p.exitValue()==0) System.out.println(stdout.toString());
else System.out.println("Can I've some debugger?");
}
}
}
According to java docs,
stdout.stop() was deprecated and even stdout.destroy() is never implemented.
For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.
you could try this instead.
String cmd="cmd /c sleep 5";
int timeout = 1;
Process p = Runtime.getRuntime().exec(cmd); //cmd is command to execute program p
ProcessResultReader stdout = new ProcessResultReader(p.getInputStream());
stdout.start();
if(!p.waitFor(timeout, TimeUnit.MILLISECONDS))
{
stdout.stop();
p.destroy();
System.out.println("Sorry, needs more time!");
System.out.flush();
}
else
{
if(p.exitValue()==0) System.out.println(stdout.toString());
else System.out.println("Can I've some debugger?");
}

Calling fortran90 exe program from java is not executing

I am trying to call Fortran 90 program from java program,
My Fortran program is as follows:
!sum.for
program Numbers_sum
implicit none
! -----------------------------------------------Declare
REAL :: a,b,sum
! -----------------------------------------------Input
print*,"Enter first number..."
read*, a
print*,"Enter second number ..."
read*, b
! -----------------------------------------------Compute
sum = a+b
! -----------------------------------------------Output
print*,"Sum =", sum
end
Which is working on Fortran compiler. And finally I got an exe file which will execute and give fortran result. I am trying to call it from my java program,
My java program as follows:
import java.io.File;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Sum {
public static void main(String []args) {
String filePath = "sum.exe";
if (new File(filePath).exists()) {
try {
ProcessBuilder pb = new ProcessBuilder(filePath);
pb.redirectError();
Process p = pb.start();
InputStream is = p.getInputStream();
int value = -1;
while ((value = is.read()) != -1) {
System.out.print((char) value);
}
int exitCode = p.waitFor();
System.out.println(filePath + " exited with " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.err.println(filePath + " does not exist");
}
}
}
But it is not working.
I am calling the java from my command prompt as follows:
But cursor blinking only. It is not working.
I did cntrl+c to escape from the java command prompt . That case I gott like the following:
Why it is not working. Please help me. How I could read that exe from my java program correctly. Any help will be appreciated!!
Seems that you need to redirect streams here--so input stream of fortran execution process would be redirected to System.in and output stream to System.out. Just put the following lines:
pb.redirectInput(Redirect.INHERIT);
pb.redirectOutput(Redirect.INHERIT);
before pb.start().

Not able to see the Perl output executing from Java class

I am using a Java class to execute a Perl script on a Linux box. The .class is being created successfully.
But when I execute the class, it says exit code successful as sop, but I'm not able to see the Perl output or the execution of the script. If I execute the Perl directly, it works fine...
This is the Perl script:
#!/usr/local/bin/perl
print ("Enter the distance to be converted:\n");
$originaldist = <STDIN>;
chop ($originaldist);
$miles = $originaldist * 0.6214;
$kilometers = $originaldist * 1.609;
print ($originaldist, " kilometers = ", $miles, " miles\n");
And this is my Java class to call the script:
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
class test {
public static void main(String[] args) throws IOException {
String[] aCmdArgs = { "perl", "-e"
, "pl newprg.pl" };
Runtime oRuntime = Runtime.getRuntime();
Process oProcess = null;
try {
oProcess = oRuntime.exec(aCmdArgs);
oProcess.waitFor();
} catch (Exception e) {
System.out.println("error executing " + aCmdArgs[0]);
}
/* dump output stream */
BufferedReader is = new BufferedReader
( new InputStreamReader(oProcess.getInputStream()));
String sLine;
while ((sLine = is.readLine()) != null) {
System.out.println(sLine);
}
System.out.flush();
/* print final result of process */
System.err.println("Exit status=" + oProcess.exitValue());
return;
}
}
Two issues:
perl -e pl newprg.pl will not actually execute your program from the command line, as it will fail to parse the given (non) expression. You probably meant to use perl newprg.pl
Your program requires input, which you will need to pipe in using the output stream of the process
For example:
try {
oProcess = oRuntime.exec(aCmdArgs);
PrintWriter writer = new PrintWriter(new OutputStreamWriter(
oProcess.getOutputStream()));
writer.println(200);
writer.close();
oProcess.waitFor();
} catch (Exception e) {
System.out.println("error executing " + aCmdArgs[0]);
}

Running shell script from Java

I am trying to run some shell scripts for Java by using commons exec package and clear the STDOUT & STDERR buffers by using PumpStreamHandler. Most of the scripts run fine without any problems but some of them hangs.
Particularly those scripts that takes some time to return. My guess is that the PumpStramHandle might be reading end of stream as there is nothing put on the stream for a while and after that the buffers fill up.
Is there any better way to get across this problem?
Extract the script/command being executed and run it yourself in a shell. When running things that are 'exec'd through some other language(c,c++, python java etc) and things start going 'wrong' this should be the first step.
You find all sorts of things going on. Scripts that stop and prompt for input(big source of hangups) errors that don't parse correctly, seg faults, files not found.
To expand on the first answer about running the commands directly to test, you can test your hypothesis with a simple script that sleeps for a while before returning output. If you
can't test your command, test your idea.
#!/bin/bash
sleep 60;
echo "if you are patient, here is your response"
Not the best solution. But does what I need. :)
class OSCommandLogger extends Thread {
private static final Logger logger = Logger.getLogger(OSCommandLogger.class);
private volatile boolean done = false;
private final String name;
// Each process is associated with an error and output stream
private final BufferedReader outputReader;
private final BufferedReader errorReader;
private final Logger log;
/**
* Reads the output & error streams of the processes and writes them to
* specified log
*
* #param p
* #param name
* #param log
*/
OSCommandLogger(Process p, String name, Logger log) {
// Create readers
outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
this.log = log;
if (name != null)
this.name = name;
else
this.name = "OSCommandStreamsLogger";
}
private void logLine(BufferedReader reader, boolean isError) {
try {
String line = null;
while ((line = reader.readLine()) != null) {
if (log != null && log.isDebugEnabled()) {
if (!isError)
log.debug("[OuputStream] " + line);
else
log.warn("[ErrorStream] " + line);
} else
logger.debug(line);
}
} catch (Exception ex) {
if (log != null)
log.error(name + ":" + "Error while reading command process stream", ex);
}
}
public void run() {
while (!done) {
logLine(outputReader, false);
logLine(errorReader, true);
try {
// Sleep for a while before reading the next lines
Thread.sleep(100);
} catch (InterruptedException e) {
log.debug("Done with command");
}
}
// Process is done. Close all the streams
try {
logLine(outputReader, false);
outputReader.close();
logLine(errorReader, true);
errorReader.close();
if (log != null && log.isDebugEnabled())
log.debug(name + ": Closed output/ error Streams.");
} catch (IOException ie) {
if (log != null)
log.error(name + ":" + "Error while reading command process stream", ie);
}
}
public void stopLoggers() {
if (log != null && log.isDebugEnabled())
log.debug(name + ":Stop loggers");
this.done = true;
}
}
Usage:
Process p = Runtime.getRuntime().exec("Command");
OSCommandLogger logger = new OSCommandLogger(p, "Command", log);
// Start the thread using thread pool
threadExec.executeRunnable(logger);
int exitValue = p.waitFor(); // Wait till the process is finished
// Required to stop the logger threads
logger.stopLoggers();
logger.interrupt();

Categories

Resources