lib/classes/isabelle/IsabelleProcess.java
changeset 25745 3f86e9dc3860
parent 25662 8c45834392e7
child 25747 be58ef74140a
equal deleted inserted replaced
25744:e2002b3657ba 25745:3f86e9dc3860
     1 /*
     1 /*
     2  * $Id$
     2  * $Id$
     3  *
       
     4  * Posix process wrapper for Isabelle (see also src/Pure/Tools/isabelle_process.ML).
       
     5  *
       
     6  * The process model:
       
     7  *
       
     8  *  (1) input
       
     9  *    - stdin stream
       
    10  *    - signals (interrupt, kill)
       
    11  *
       
    12  *  (2) output/results
       
    13  *    - stdout stream, interspersed with marked Isabelle messages
       
    14  *    - stderr stream
       
    15  *    - process exit (return code)
       
    16  *
       
    17  * I/O is fully asynchronous, with unrestricted buffers.  Text is encoded as UTF-8.
       
    18  * 
       
    19  * System properties:
       
    20  * 
       
    21  *   isabelle.home      ISABELLE_HOME of Isabelle installation
       
    22  *                      (default determined from isabelle-process via PATH)
       
    23  *   isabelle.shell     optional shell command for isabelle-process (also requires isabelle.home)
       
    24  *   isabelle.kill      optional kill command (default "kill")
       
    25  */
     3  */
    26 
     4 
    27 package isabelle;
     5 package isabelle;
    28 
     6 
    29 import java.io.*;
     7 import java.io.*;
    30 import java.util.ArrayList;
     8 import java.util.ArrayList;
    31 import java.util.Locale;
     9 import java.util.Locale;
    32 import java.util.concurrent.LinkedBlockingQueue;
    10 import java.util.concurrent.LinkedBlockingQueue;
       
    11 
       
    12 /**
       
    13  * Posix process wrapper for Isabelle (see also <code>src/Pure/Tools/isabelle_process.ML</code>).
       
    14  * <p>
       
    15  * 
       
    16  * The process model:
       
    17  * <p>
       
    18  *
       
    19  * <ol>
       
    20  * <li> input
       
    21  * <ul>
       
    22  * <li> stdin stream
       
    23  * <li> signals (interrupt, kill)
       
    24  * </ul>
       
    25  *
       
    26  * <li> output/results
       
    27  * <ul>
       
    28  * <li> stdout stream, interspersed with marked Isabelle messages
       
    29  * <li> stderr stream
       
    30  * <li> process exit (return code)
       
    31  * </ul>
       
    32  * </ol>
       
    33  * 
       
    34  * I/O is fully asynchronous, with unrestricted buffers.  Text is encoded as UTF-8.
       
    35  * <p>
       
    36  * 
       
    37  * System properties:
       
    38  * <p>
       
    39  * 
       
    40  * <dl>
       
    41  * <dt> <code>isabelle.home</code>  <di> <code>ISABELLE_HOME</code> of Isabelle installation
       
    42  *                      (default determined from isabelle-process via <code>PATH</code>)
       
    43  * <dt> <code>isabelle.shell</code> <di> optional shell command for <code>isabelle-process</code> (also requires isabelle.home)
       
    44  * <dt> <code>isabelle.kill</code>  <di> optional kill command (default <code>kill</code>)
       
    45  */
    33 
    46 
    34 public class IsabelleProcess {
    47 public class IsabelleProcess {
    35     private volatile Process proc = null;
    48     private volatile Process proc = null;
    36     private volatile String pid = null;
    49     private volatile String pid = null;
    37     private volatile boolean closing = false;
    50     private volatile boolean closing = false;
    38     private LinkedBlockingQueue<String> output = null;
    51     private LinkedBlockingQueue<String> output = null;
    39 
    52 
    40 
    53 
    41     /* exceptions */
    54     /**
    42 
    55      * Models failures in process management.
       
    56      */
    43     public static class IsabelleProcessException extends Exception {
    57     public static class IsabelleProcessException extends Exception {
    44         public IsabelleProcessException() {
    58         public IsabelleProcessException() {
    45             super();
    59             super();
    46         }
    60         }
    47         public IsabelleProcessException(String msg) {
    61         public IsabelleProcessException(String msg) {
    48             super(msg);
    62             super(msg);
    49         }
    63         }
    50     };
    64     };
    51 
    65 
    52 
    66 
    53     /* results from the process */
    67     /**
    54 
    68      * Models cooked results from the process.
       
    69      */
    55     public static class Result {
    70     public static class Result {
    56         public enum Kind {
    71         public enum Kind {
    57             STDIN, STDOUT, STDERR, SIGNAL, EXIT,                // Posix channels/events
    72             STDIN, STDOUT, STDERR, SIGNAL, EXIT,                // Posix channels/events
    58             WRITELN, PRIORITY, TRACING, WARNING, ERROR, DEBUG,  // Isabelle messages
    73             WRITELN, PRIORITY, TRACING, WARNING, ERROR, DEBUG,  // Isabelle messages
    59             SYSTEM                                              // internal system notification
    74             SYSTEM                                              // internal system notification
    69         public String toString() {
    84         public String toString() {
    70             return this.kind.toString() + " [[" + this.result + "]]";
    85             return this.kind.toString() + " [[" + this.result + "]]";
    71         }
    86         }
    72     }
    87     }
    73 
    88 
       
    89 
       
    90     /**
       
    91      * Main result queue -- accumulates cooked messages asynchronously.
       
    92      */
    74     public LinkedBlockingQueue<Result> results;
    93     public LinkedBlockingQueue<Result> results;
    75 
    94 
    76     private synchronized void putResult(Result.Kind kind, String result) {
    95     private synchronized void putResult(Result.Kind kind, String result) {
    77         try {
    96         try {
    78             results.put(new Result(kind, result));
    97             results.put(new Result(kind, result));
    79         } catch (InterruptedException exn) {  }
    98         } catch (InterruptedException exn) {  }
    80     }
    99     }
    81 
   100 
    82 
   101 
    83     /* interrupt process */
   102     /**
    84 
   103      * Interrupts Isabelle process via Posix signal.
       
   104      * @throws isabelle.IsabelleProcess.IsabelleProcessException
       
   105      */
    85     public synchronized void interrupt() throws IsabelleProcessException
   106     public synchronized void interrupt() throws IsabelleProcessException
    86     {
   107     {
    87         if (proc != null && pid != null) {
   108         if (proc != null && pid != null) {
    88             String kill = System.getProperty("isabelle.kill", "kill");
   109             String kill = System.getProperty("isabelle.kill", "kill");
    89             String [] cmdline = {kill, "-INT", pid};
   110             String [] cmdline = {kill, "-INT", pid};
   102             throw new IsabelleProcessException("Cannot interrupt: no process");
   123             throw new IsabelleProcessException("Cannot interrupt: no process");
   103         }
   124         }
   104     }
   125     }
   105 
   126 
   106 
   127 
   107     /* kill process */
   128     /**
   108 
   129      * Kills Isabelle process: try close -- sleep -- destroy.
       
   130      */
   109     public synchronized void kill() throws IsabelleProcessException
   131     public synchronized void kill() throws IsabelleProcessException
   110     {
   132     {
   111         if (proc != null) {
   133         if (proc != null) {
   112             tryClose();
   134             tryClose();
   113             try {
   135             try {
   120             throw new IsabelleProcessException("Cannot kill: no process");
   142             throw new IsabelleProcessException("Cannot kill: no process");
   121         }
   143         }
   122     }
   144     }
   123 
   145 
   124 
   146 
   125     /* encode text as string token */
   147     /**
   126 
   148      * Auxiliary operation to encode text as Isabelle string token.
       
   149      */
   127     public static String encodeString(String str) {
   150     public static String encodeString(String str) {
   128         Locale locale = null;
   151         Locale locale = null;
   129         StringBuffer buf = new StringBuffer(100);
   152         StringBuffer buf = new StringBuffer(100);
   130         int i;
   153         int i;
   131         char c;
   154         char c;
   174     private OutputThread outputThread;
   197     private OutputThread outputThread;
   175 
   198 
   176 
   199 
   177     // public operations
   200     // public operations
   178 
   201 
       
   202     /**
       
   203      * Feeds arbitrary text into the process.
       
   204      */
   179     public synchronized void output(String text) throws IsabelleProcessException
   205     public synchronized void output(String text) throws IsabelleProcessException
   180     {
   206     {
   181         if (proc != null && !closing) {
   207         if (proc != null && !closing) {
   182             try {
   208             try {
   183                 output.put(text);
   209                 output.put(text);
   189         } else {
   215         } else {
   190             throw new IsabelleProcessException("Cannot output: already closing");
   216             throw new IsabelleProcessException("Cannot output: already closing");
   191         }
   217         }
   192     }
   218     }
   193 
   219 
       
   220     /**
       
   221      * Closes Isabelle process input, causing termination eventually.
       
   222      */
   194     public synchronized void close() throws IsabelleProcessException
   223     public synchronized void close() throws IsabelleProcessException
   195     {
   224     {
   196         output("\u0000");
   225         output("\u0000");
   197         closing = true;
   226         closing = true;
   198         // FIXME watchdog/timeout
   227         // FIXME watchdog/timeout
   199     }
   228     }
   200 
   229 
       
   230     /**
       
   231      * Closes Isabelle process input, causing termination eventually -- unless process already terminated.
       
   232      */
   201     public synchronized void tryClose()
   233     public synchronized void tryClose()
   202     {
   234     {
   203         if (proc != null && !closing) {
   235         if (proc != null && !closing) {
   204             try {
   236             try {
   205                 close();
   237                 close();
   210     private synchronized void outputSync(String text) throws IsabelleProcessException
   242     private synchronized void outputSync(String text) throws IsabelleProcessException
   211     {
   243     {
   212         output(" \\<^sync>\n; " + text + " \\<^sync>;\n");
   244         output(" \\<^sync>\n; " + text + " \\<^sync>;\n");
   213     }
   245     }
   214 
   246 
       
   247     /**
       
   248      * Feeds exactly one Isabelle command into the process. 
       
   249      */
   215     public synchronized void command(String text) throws IsabelleProcessException
   250     public synchronized void command(String text) throws IsabelleProcessException
   216     {
   251     {
   217         outputSync("Isabelle.command " + encodeString(text));
   252         outputSync("Isabelle.command " + encodeString(text));
   218     }
   253     }
   219 
   254 
       
   255     /**
       
   256      * Feeds ML toplevel declarations into the process.
       
   257      */
   220     public synchronized void ML(String text) throws IsabelleProcessException
   258     public synchronized void ML(String text) throws IsabelleProcessException
   221     {
   259     {
   222         outputSync("ML " + encodeString(text));
   260         outputSync("ML " + encodeString(text));
   223     }
   261     }
   224 
   262 
   348         }
   386         }
   349     }
   387     }
   350     private ExitThread exitThread;
   388     private ExitThread exitThread;
   351 
   389 
   352 
   390 
   353     /* create process */
   391     /**
   354 
   392      * Creates Isabelle process with specified logic image.
       
   393      */
   355     public IsabelleProcess(String logic) throws IsabelleProcessException
   394     public IsabelleProcess(String logic) throws IsabelleProcessException
   356     {
   395     {
   357         ArrayList<String> cmdline = new ArrayList<String> ();
   396         ArrayList<String> cmdline = new ArrayList<String> ();
   358         String shell = null;
   397         String shell = null;
   359         String home = null;
   398         String home = null;
   403         inputThread.start();
   442         inputThread.start();
   404         errorThread.start();
   443         errorThread.start();
   405         exitThread.start();
   444         exitThread.start();
   406     }
   445     }
   407     
   446     
       
   447     /**
       
   448      * Creates Isabelle process with default logic image.
       
   449      */
   408     public IsabelleProcess() throws IsabelleProcessException {
   450     public IsabelleProcess() throws IsabelleProcessException {
   409         this(null);
   451         this(null);
   410     }
   452     }
   411 }
   453 }