test/java/lang/Runtime/exec/SleepyCat.java

Print this page




  56 
  57         public boolean timedOut() {
  58             return timedOut;
  59         }
  60     }
  61 
  62     private static boolean hang1() throws IOException, InterruptedException {
  63         // Time out was reproducible on Solaris 50% of the time;
  64         // on Linux 80% of the time.
  65         //
  66         // Scenario: After fork(), parent executes and closes write end of child's stdin.
  67         // This causes child to retain a write end of the same pipe.
  68         // Thus the child will never see an EOF on its stdin, and will hang.
  69         Runtime rt = Runtime.getRuntime();
  70         // Increasing the iteration count makes the bug more
  71         // reproducible not only for the obvious reason, but also for
  72         // the subtle reason that it makes reading /proc/getppid()/fd
  73         // slower, making the child more likely to win the race!
  74         int iterations = 20;
  75         int timeout = 30;
  76         String[] catArgs   = new String[] {"/bin/cat"};
  77         String[] sleepArgs = new String[] {"/bin/sleep",
  78                                             String.valueOf(timeout+1)};
  79         Process[] cats   = new Process[iterations];
  80         Process[] sleeps = new Process[iterations];
  81         Timer timer = new Timer(true);
  82         TimeoutTask catExecutioner = new TimeoutTask(cats);
  83         timer.schedule(catExecutioner, timeout * 1000);
  84 
  85         for (int i = 0; i < cats.length; ++i) {
  86             cats[i] = rt.exec(catArgs);
  87             java.io.OutputStream s = cats[i].getOutputStream();
  88             Process sleep = rt.exec(sleepArgs);
  89             s.close(); // race condition here
  90             sleeps[i] = sleep;
  91         }
  92 
  93         for (int i = 0; i < cats.length; ++i)
  94             cats[i].waitFor(); // hangs?
  95 
  96         timer.cancel();
  97 


 109         // Time out was reproducible on Linux 80% of the time;
 110         // never on Solaris because of explicit close in Solaris-specific code.
 111 
 112         // Scenario: After fork(), the parent naturally closes the
 113         // child's stdout write end.  The child dup2's the write end
 114         // of its stdout onto fd 1.  On Linux, it fails to explicitly
 115         // close the original fd, and because of the parent's close()
 116         // of the fd, the child retains it.  The child thus ends up
 117         // with two copies of its stdout.  Thus closing one of those
 118         // write fds does not have the desired effect of causing an
 119         // EOF on the parent's read end of that pipe.
 120         Runtime rt = Runtime.getRuntime();
 121         int iterations = 10;
 122         Timer timer = new Timer(true);
 123         int timeout = 30;
 124         Process[] backgroundSleepers = new Process[iterations];
 125         TimeoutTask sleeperExecutioner = new TimeoutTask(backgroundSleepers);
 126         timer.schedule(sleeperExecutioner, timeout * 1000);
 127         byte[] buffer = new byte[10];
 128         String[] args =
 129             new String[] {"/bin/sh", "-c",
 130                           "exec sleep " + (timeout+1) + " >/dev/null"};

 131 
 132         for (int i = 0;
 133              i < backgroundSleepers.length && !sleeperExecutioner.timedOut();
 134              ++i) {
 135             backgroundSleepers[i] = rt.exec(args); // race condition here
 136             try {
 137                 // should get immediate EOF, but might hang
 138                 if (backgroundSleepers[i].getInputStream().read() != -1)
 139                     throw new Exception("Expected EOF, got a byte");
 140             } catch (IOException e) {
 141                 // Stream closed by sleeperExecutioner
 142                 break;
 143             }
 144         }
 145 
 146         timer.cancel();
 147 
 148         destroy(backgroundSleepers);
 149 
 150         if (sleeperExecutioner.timedOut())


  56 
  57         public boolean timedOut() {
  58             return timedOut;
  59         }
  60     }
  61 
  62     private static boolean hang1() throws IOException, InterruptedException {
  63         // Time out was reproducible on Solaris 50% of the time;
  64         // on Linux 80% of the time.
  65         //
  66         // Scenario: After fork(), parent executes and closes write end of child's stdin.
  67         // This causes child to retain a write end of the same pipe.
  68         // Thus the child will never see an EOF on its stdin, and will hang.
  69         Runtime rt = Runtime.getRuntime();
  70         // Increasing the iteration count makes the bug more
  71         // reproducible not only for the obvious reason, but also for
  72         // the subtle reason that it makes reading /proc/getppid()/fd
  73         // slower, making the child more likely to win the race!
  74         int iterations = 20;
  75         int timeout = 30;
  76         String[] catArgs   = new String[] {UnixCommands.cat()};
  77         String[] sleepArgs = new String[] {UnixCommands.sleep(),
  78                                             String.valueOf(timeout+1)};
  79         Process[] cats   = new Process[iterations];
  80         Process[] sleeps = new Process[iterations];
  81         Timer timer = new Timer(true);
  82         TimeoutTask catExecutioner = new TimeoutTask(cats);
  83         timer.schedule(catExecutioner, timeout * 1000);
  84 
  85         for (int i = 0; i < cats.length; ++i) {
  86             cats[i] = rt.exec(catArgs);
  87             java.io.OutputStream s = cats[i].getOutputStream();
  88             Process sleep = rt.exec(sleepArgs);
  89             s.close(); // race condition here
  90             sleeps[i] = sleep;
  91         }
  92 
  93         for (int i = 0; i < cats.length; ++i)
  94             cats[i].waitFor(); // hangs?
  95 
  96         timer.cancel();
  97 


 109         // Time out was reproducible on Linux 80% of the time;
 110         // never on Solaris because of explicit close in Solaris-specific code.
 111 
 112         // Scenario: After fork(), the parent naturally closes the
 113         // child's stdout write end.  The child dup2's the write end
 114         // of its stdout onto fd 1.  On Linux, it fails to explicitly
 115         // close the original fd, and because of the parent's close()
 116         // of the fd, the child retains it.  The child thus ends up
 117         // with two copies of its stdout.  Thus closing one of those
 118         // write fds does not have the desired effect of causing an
 119         // EOF on the parent's read end of that pipe.
 120         Runtime rt = Runtime.getRuntime();
 121         int iterations = 10;
 122         Timer timer = new Timer(true);
 123         int timeout = 30;
 124         Process[] backgroundSleepers = new Process[iterations];
 125         TimeoutTask sleeperExecutioner = new TimeoutTask(backgroundSleepers);
 126         timer.schedule(sleeperExecutioner, timeout * 1000);
 127         byte[] buffer = new byte[10];
 128         String[] args =
 129             new String[] {UnixCommands.sh(), "-c",
 130                           "exec " + UnixCommands.sleep() + " "
 131                                   + (timeout+1) + " >/dev/null"};
 132 
 133         for (int i = 0;
 134              i < backgroundSleepers.length && !sleeperExecutioner.timedOut();
 135              ++i) {
 136             backgroundSleepers[i] = rt.exec(args); // race condition here
 137             try {
 138                 // should get immediate EOF, but might hang
 139                 if (backgroundSleepers[i].getInputStream().read() != -1)
 140                     throw new Exception("Expected EOF, got a byte");
 141             } catch (IOException e) {
 142                 // Stream closed by sleeperExecutioner
 143                 break;
 144             }
 145         }
 146 
 147         timer.cancel();
 148 
 149         destroy(backgroundSleepers);
 150 
 151         if (sleeperExecutioner.timedOut())