Link to home
Start Free TrialLog in
Avatar of hoomanv
hoomanvFlag for Canada

asked on

The process does not terminate, nor does die

Hi experts
I have written a c program that generates a runtime error here is the code
char a[3];
a[5645456] = 0; // out-of-bounds array access
consider a.exe exploits this code to generate a runtime error.
Ok my problem is arising from this. In java I start a new process to execute a.exe in a single thread (named ExecutorThread) and another thread (named SimultaneousReader) to simultaneously read the output from the process’s inputstream. My ExecutorThread then calls process.waitFor() and waits till its finished. In main() I call executorThread.join(3000) to not wait more than 3 seconds for the process to be finished and after timeout a call to process.destroy() is made. As we expect that error occurs during the execution so windows will popup a message box telling you that “a.exe has encountered a problem and needs to be closed”, forcing you to press the button to terminate the process. So, if you don’t respond within 3 seconds, destroy method will be called to kill the process, although it fails to kill, but surprisingly the executorThread that was waiting since the call to process.waitFor() will resume, but the bad news is that the SimultaneousReader is still blocked waiting to read the next byte from inputstream. there is no way to interrupt it unless I ask it from OS. These two threads are used in software and there would be no man who interactively discards runtime errors that may occur during the job. So definitely I need a way to release the lock on SimultaneousReader and prepare it to accept new jobs (somewhat works like a thread pool). Any comment would be appreciated. If your solution is about non-blocking IO operations, please tell me exactly how to do it with traditional java.io.
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Try also closing the stream it is reading when you kill the process.
Avatar of hoomanv

ASKER

CEHJ: I'm going to test it, wait ...
objects: inputstream.close() also blocks
In case i wasn't clear, i meant use a concurrent class that will provide you with one, rather than constructing your own Thread
> objects: inputstream.close() also blocks

sounds like its blocked at the OS level

Try calling available() before doing a read() only call read() if there are bytes available. That way it won't block.
Avatar of hoomanv

ASKER

unfortunatly InputStream.available() always returns 0; // javadoc says

CEHJ would you please write a sample code ? im not familiar with that package
> unfortunatly InputStream.available() always returns 0; // javadoc says

Thats for the base class :)
It returns the number of bytes available for reading, it wouldn't be much use if it always returned 0.
Avatar of hoomanv

ASKER

I also tested it on the Process's InputStream
thats all the thing that it does, always returns 0
I have seen the java source code for FileInputStream and I discoverd the available method is implemented at native level. so, does Process also implemente it too ? i think its a wreakness of this class
>>Try calling available() before doing a read() only call read() if there are bytes available

That won't necessarily be that useful. In the case of a BufferedInputStream it won't really help you to continue reading the stream but effectively only tell you the number of bytes that have already been read
>>In the case of a BufferedInputStream

(e.g.)
You don't want to be using a buffered input stream, that would defaeaqt the purpose of what u are trying to achieve.
You should be using the output syttream of the process directly.
Avatar of hoomanv

ASKER

wrapping the IS in a BufferedInputStream does not help neither. all it does is just calling the IS.available() and as I said before the Process's IS has not implemented available() to return correctly (I guess)

currently im reading the introduced java.util.concurrent to find something usefull (I also found that java 1.5 has a built in thread pooling support), but I think I have to rewrite my own thread to be able to use it in this way.
shortly SimulatanousReader is doing this:

run() {
    while(running) {
        is there any IS to read from ?
        if no
             wait until someone notifies me
        read the entire input into buffer // this is the blocking line
        do somthing
    }
}

it seems i have to reimplement the entire class. i'll work on it but is it guaranteed 100% to solve the blocking issue ? is there any other way ? I just suggested that it may be solved by using non-blocking IO but I think the are other ways to overcome this
>>You don't want to be using a buffered input stream,

I wasn't suggesting one

>>it seems i have to reimplement the entire class.

Your class simply needs to implement Runnable
:-)
> and as I said before the Process's IS has not implemented available() to return correctly (I guess)

It does implement it correctly. Have used it many times to stop this exact problem :)

Just killing the the thread is going to still leave blocked resources.
Did you get it going?
Avatar of hoomanv

ASKER

hmm ?
What's the status?
Avatar of hoomanv

ASKER

when windows takes control of the exe, even a call to available blocks. another way to overcome this is to use InterruptibleChannel but Process just gives me an inputstream not a channel. these two fails for me. you told me to use classes in java.util.concurrent but i dont have any idea on how to use them. im not clearly understand how these would help til I see an example. sorry I cant get the idea behind that
Avatar of hoomanv

ASKER

another problem i have with process, when the a.exe is expected to do somthinf like this:

main() {
    printf("hello"); // only 5 characters
    while(true)
        ;
}

then the ExecutorThread waits for ever. if destroy the process and it successfully kills. BUT. if i call process.getExcitCode() i got an InterruptedThreadStateException although the process is not running. and another severe problem: i cant access to the printed "hello" world from process. whu ? i found that if process prints more than 1024 byte the output is obtainable but in the case that I kill the process, output bytes less than 1024 would disapear. trying to call "cmd /c a.exe < in > out" can solve the issue but it brings another problem. process.destroy only kills the cmd and not the subprocess "a.exe".
Why does main look like that? It doesn't exit
So why exactly did u accept the first comment?
Avatar of hoomanv

ASKER

> Why does main look like that? It doesn't exit
some students have done their HWs and this app is engaged to run them. thus it must be prepared for encounter with such apps.

> So why exactly did u accept the first comment?
Honestly I was wrong
then you should reopen the q, we're not supposed to post to closed questions.
Avatar of hoomanv

ASKER

how to do it ?
>>thus it must be prepared for encounter with such apps.

OK, but this makes things trickier. You need to handle *both* streams from the app (i.e. the error stream too) in separate threads and then be prepared to terminate the process yourself as *it* doesn't
 while(true)
        ;

you never want to write code like that :)
> i cant access to the printed "hello" world from process. whu ?

the output is buffered, you'll need to flush the buffer.
And make sure you're not using a buufer on the recieving side either :)
Avatar of hoomanv

ASKER

ProcessBuilder has an option to redirecting error stream to stdin. its not problem.

> you never want to write code like that :)
its just an example of such an unqualified application. consider any other loop for evers
you shouldn't need to use a loop at all to do a wait, waste of CPU

>>ProcessBuilder has an option to redirecting error stream to stdin. its not problem.

Yes, that should get you round that one
Avatar of hoomanv

ASKER

> the output is buffered, you'll need to flush the buffer.

i said its ok when while(for ever) does not exist i can read output finely. but if the exist, and i destroy the app after a while. the output is not accessible only if the output is less that an amount may be 1024
> if i call process.getExcitCode() i got an InterruptedThreadStateException although the process is not running

have you tried calling waitFor() before getting the exit code.
> but if the exist, and i destroy the app after a while. the output is not accessible only if the output is less that an amount may be 1024

yes cause terminating it doesn't give it a chance to flush the buffers and they get lost.
Avatar of hoomanv

ASKER

> have you tried calling waitFor() before getting the exit code.
yes i have. it doesn't make any sense. any way i cant grab the output.
>>have you tried calling waitFor() before getting the exit code.

You'll be waiting a long time in the case of the above ;-)
Avatar of hoomanv

ASKER

my prob is not just
while(true)
    ;
as i said the below is the critical problem
array[6453234] = 0; // out of bound
in this case OS interferes and takes control of execution and then ANY INPUT OPERATION will block.
Difficult with a small amount of detail to know what's (not) happening, but you can get into such tight loops that processing anything else becomes difficult
can you use a seperate (native) wrapper application to handle the running of the application and handling of any exceptions, and instead call that app from java. That way you'll have better control of the behaviour of the application that java calls.
Avatar of hoomanv

ASKER

> use a seperate (native) wrapper application
seems to be the last chance. i also need to run the app as another user to restrict its priviledges. i tried sysinternals PSEXEC but it does not have an option to kill the process after X seconds. i have to write my own RUNAS
sounds like using a native appo would solve a lot of your problems and give you a lot more control.
Try ProcessKill
Sorry - taskkill
Avatar of hoomanv

ASKER

yes the answer is native. but how can we call it java ?
trying to call a process to run the app and the after x seconds running another process to kill that app what a nasty what a nasty job , 3 process for each run
why do you need a seperate instance of each for every job?  can't you have the manager apps manging more than 1 job?
Avatar of hoomanv

ASKER

> can't you have the manager apps manging more than 1 job?
which native manager app would do it ? such a big manage is just the OS. and if i want to write my own, i would then re write all the java app in c++
the java app would certainly have no problem managing multiple processes.
and the native app could possibly avoid starting a new process by calling the c program directly.
what form are the apps to run being delivered?
Avatar of hoomanv

ASKER

> what form are the apps to run being delivered?
they are just console applications. read somthing from stdin or a file and calculating the results then output either in a file or stdout.
Try this - it works to some extent for me:


/**
 * 30-Mar-2006
 */

package concurrent;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author Charles
 */
public class RunAndTerminate {

      public void startAndStop(long maxRunTimeInSeconds) {
            ProcessBuilder pb = new ProcessBuilder();
            pb
                        .command(new String[] { "C:/DOCUME~1/Charles/MYDOCU~1/java/dumpit/loop.exe" });
            pb.redirectErrorStream(true);
            ExecutorService runners = null;
            Process p = null;
            boolean terminatedNormally = false;
            try {
                  p = pb.start();
                  runners = Executors.newFixedThreadPool(1);
                  try {
                        runners.execute(new ProcessHandler(p));
                        terminatedNormally = runners.awaitTermination(maxRunTimeInSeconds,
                                    TimeUnit.SECONDS);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
            } catch (IOException e) {
                  e.printStackTrace();
            } finally {
                  System.out.printf("Terminated normally? - %b\n", terminatedNormally);
                  // p.destroy(); (Won't work)
                  if (!terminatedNormally) {
                        doNativeShutdown();
                  }
                  runners.shutdown();
            }
      }

      private void doNativeShutdown() {

            try {
                  ProcessBuilder pb = new ProcessBuilder();
                  pb.command(new String[] { "taskkill", "/IM", "loop.exe" });
                  pb.start();
            } catch (IOException e) {
                  e.printStackTrace();
            }

      }

      public static void main(String[] args) {
            new RunAndTerminate().startAndStop(10L);
            System.out.println("All finished!");

      }

      private class ProcessHandler implements Runnable {
            private Process p;

            public ProcessHandler(Process p) {
                  this.p = p;
            }

            public void run() {
                  int buf = -1;
                  InputStreamReader in = null;
                  try {
                        in = new InputStreamReader(p.getInputStream());
                        System.out.println("Attempting to read process output...");
                        while ((buf = in.read()) > -1) {
                              System.out.print((char) buf);
                        }
                  } catch (IOException e) {
                        e.printStackTrace();
                  } finally {
                        try {
                              in.close();
                        } catch (IOException e) {
                        }
                  }

            }

      }

}
btw, the native code is the following:


#include <stdio.h>


main() {
        printf("%s\n", "Starting...");
        for(;;) {
              sleep(10);
        }
}
>     printf("%s\n", "Starting...");

try it with:

    printf("%s", "Starting...");

plus the multitude of other error conditions that could occur.
Its easy to write something to handle a specific case,. handling *all* cases is the tricky bit.