Changeset 31707

Show
Ignore:
Timestamp:
26.05.2017 19:43:28 (2 years ago)
Author:
ak19
Message:

Adding an option to cancelProcess() that allows you to force the caller, even if it's a GUI thread, to wait until the cancelProcess() method's end (which ends when the SafeProcess? becomes interruptible). There's now a default cancelProcess() again, that takes no arguments, and this is what we call. It behaves as before: if called from a GUI thread, it won't wait for the SafeProcess? to become interruptible.

Location:
main/trunk
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java

    r31706 r31707  
    4343    public static String WIN_KILL_CMD; 
    4444 
    45     /** 
    46     * Boolean interruptible is used to mark any sections of blocking code that should not be interrupted 
    47     * with an InterruptedExceptions. At present only the cancelRunningProcess() attempts to do such a thing 
    48     * and avoids doing so when interruptible is false. 
    49     * Note that interruptible is also used as a lock, so remember to synchronize on it when using it! 
    50     */ 
     45    /** 
     46    * Boolean interruptible is used to mark any sections of blocking code that should not be interrupted 
     47    * with an InterruptedExceptions. At present only the cancelRunningProcess() attempts to do such a thing 
     48    * and avoids doing so when interruptible is false. 
     49    * Note that interruptible is also used as a lock, so remember to synchronize on it when using it! 
     50     */ 
    5151    public Boolean interruptible = Boolean.TRUE;  
    5252     
     
    7676    // allow callers to process exceptions of the main process thread if they want 
    7777    private ExceptionHandler exceptionHandler = null; 
    78     /** allow callers to implement hooks that get called during the main phases of the internal 
    79     * process' life cycle, such as before and after process.destroy() gets called 
    80     */ 
     78    /** allow callers to implement hooks that get called during the main phases of the internal 
     79    * process' life cycle, such as before and after process.destroy() gets called 
     80     */ 
    8181    private MainProcessHandler mainHandler = null; 
    8282 
     
    127127 
    128128    /** to set a handler that will handle the main (SafeProcess) thread, 
    129     * implementing the hooks that will get called during the internal process' life cycle, 
     129    * implementing the hooks that will get called during the internal process' life cycle, 
    130130     * such as before and after process.destroy() is called */ 
    131131    public void setMainHandler(MainProcessHandler handler) { 
     
    153153 
    154154    /** 
    155      * Call this method when you want to prematurely and safely terminate any process 
    156      * that SafeProcess may be running. 
    157      * You may want to implement the SafeProcess.MainHandler interface to write code 
    158      * for any hooks that will get called during the process' life cycle. 
    159      * @return false if process has already terminated or if it was already terminating 
    160      * when cancel was called. In such cases no interrupt is sent. Returns boolean sentInterrupt. 
     155     * If calling this method from a GUI thread when the SafeProcess is in the uninterruptible 
     156     * phase of natural termination, then this method will return immediately before that phase 
     157     * has ended. To force the caller to wait until the natural termination phase has ended, 
     158     * call the other variant of this method with param forceWaitUntilInterruptible set to true: 
     159     * cancelRunningProcess(true). 
     160     * @return false if process has already terminated or if it was already terminating when 
     161     * cancel was called. In such cases no interrupt is sent. 
     162     * This method returns a boolean that you can call sentInterrupt.   
    161163     */ 
    162     public synchronized boolean cancelRunningProcess() { 
     164    public boolean cancelRunningProcess() {  
     165 
     166    boolean forceWaitUntilInterruptible = true; 
     167    // by default, event dispatch threads may not want to wait for any joins() taking 
     168    // place at the time of cancel to be completed. 
     169    // So don't wait until the SafeProcess becomes interruptible 
     170    return this.cancelRunningProcess(!forceWaitUntilInterruptible); 
     171    } 
     172 
     173    /** 
     174     * Call this method when you want to prematurely and safely terminate any process 
     175     * that SafeProcess may be running. 
     176     * You may want to implement the SafeProcess.MainHandler interface to write code 
     177     * for any hooks that will get called during the process' life cycle. 
     178     * @param forceWaitUntilInterruptible if set to true by a calling GUI thread, then this method 
     179     * won't return until the running process is interruptible, even if SafeProcess is in the phase 
     180     * of naturally terminating, upon which no interrupts will be sent to the SafeProcess 
     181     * thread anyway. The join() calls within SafeProcess.runProcess() are blocking calls and are 
     182     * therefore sensitive to InterruptedExceptions. But the join() calls are part of the cleanup 
     183     * phase and shouldn't be interrupted, and nothing thereafter can be interrupted anyway. 
     184     * This method tends to be called with the param set to false. In that case, if the SafeProcess 
     185     * is in an uninterruptible phase (as can then only happen during clean up of natural 
     186     * termination) then a calling GUI thread will just return immediately. Meaning, the GUI thread 
     187     * won't wait for the SafeProcess thread to finish cleaning up. 
     188     * @return false if process has already terminated or if it was already terminating when 
     189     * cancel was called. In such cases no interrupt is sent. 
     190     * This method returns a boolean that you can call sentInterrupt. 
     191     */ 
     192    public synchronized boolean cancelRunningProcess(boolean forceWaitUntilInterruptible) { 
    163193    // on interrupt: 
    164194    // - forciblyTerminate will be changed to true if the interrupt came in when the process was 
     
    182212    // have to wait until afterward      
    183213    if (interruptible) { 
    184         // either way, we can now interrupt the thread - if we have one (we should) 
    185         if(this.theProcessThread != null) { // we're told which thread should be interrupted 
     214        // either way, we can now interrupt the thread that SafeProcess.runProcess() is running in 
     215        if(this.theProcessThread != null) { // we stored a ref to the main thread that's to be interrupted 
    186216        this.theProcessThread.interrupt(); 
    187217        log("@@@ Successfully sent interrupt to process."); 
     
    189219        } 
    190220    } 
    191     else { // wait for join()s to finish. 
     221    else { // wait for join()s to finish, if we've been asked to wait 
     222         
    192223        // During and after joining(), there's no need to interrupt any more anyway: no calls 
    193         // subsequent to joins() block, so everything thereafter is insensitive to InterruptedExceptions. 
    194  
    195         if(SwingUtilities.isEventDispatchThread()) { 
     224        // subsequent to joins() block, so everything thereafter is insensitive to InterruptedExceptions 
     225        // and everything from the joins() onward are cleanup on natural process termination, so no 
     226        // interrupt is needed after the joins().  
     227        // Still, even if the caller is a GUI thread, they can decide if they want to wait until this 
     228        // method's end: until the SafeProcess becomes interruptible again 
     229 
     230        if(!forceWaitUntilInterruptible && SwingUtilities.isEventDispatchThread()) { 
    196231        log("#### Event Dispatch thread, returning"); 
    197232        return false; 
     
    757792// but the other suggestion did work: pkill -TERM -P pid did work 
    758793// More reading: 
     794// https://superuser.com/questions/343031/sigterm-with-a-keyboard-shortcut 
     795// Ctrl-C sends a SIGNINT, not SIGTERM or SIGKILL. And on Ctrl-C, "the signal is sent to the foreground *process group*." 
    759796// https://linux.die.net/man/1/kill (manual) 
    760797// https://unix.stackexchange.com/questions/117227/why-pidof-and-pgrep-are-behaving-differently 
     
    765802 
    766803/** 
    767  * On Unix, will kill the process denoted by processID and any subprocessed this launched. Tested on a Mac, where this is used. 
     804 * On Unix, will kill the process denoted by processID and any subprocesses this launched. Tested on a Mac, where this is used. 
    768805 * @param force if true will send the -KILL (-9) signal, which may result in abrupt termination without cleanup 
    769806 * if false, will send the -TERM (-15) signal, which will allow cleanup before termination. Sending a SIGTERM is preferred. 
     
    810847    // the process and its subprocesses (don't need to call this method at all to terminate the processes: the processes 
    811848    // aren't running when we get to this method) 
    812     log("@@@ Sending termination signal returned exit value 1. On unix this happens when the process has already been terminated."); 
     849    log("@@@ Sending termination signal returned exit value 1. On unix this can happen when the process has already been terminated."); 
    813850    return true; 
    814851    } else { 
  • main/trunk/greenstone3/src/java/org/greenstone/util/SafeProcess.java

    r31706 r31707  
    4343    public static String WIN_KILL_CMD; 
    4444 
    45     /** 
    46     * Boolean interruptible is used to mark any sections of blocking code that should not be interrupted 
    47     * with an InterruptedExceptions. At present only the cancelRunningProcess() attempts to do such a thing 
    48     * and avoids doing so when interruptible is false. 
    49     * Note that interruptible is also used as a lock, so remember to synchronize on it when using it! 
    50     */ 
     45    /** 
     46    * Boolean interruptible is used to mark any sections of blocking code that should not be interrupted 
     47    * with an InterruptedExceptions. At present only the cancelRunningProcess() attempts to do such a thing 
     48    * and avoids doing so when interruptible is false. 
     49    * Note that interruptible is also used as a lock, so remember to synchronize on it when using it! 
     50     */ 
    5151    public Boolean interruptible = Boolean.TRUE;  
    5252     
     
    7676    // allow callers to process exceptions of the main process thread if they want 
    7777    private ExceptionHandler exceptionHandler = null; 
    78     /** allow callers to implement hooks that get called during the main phases of the internal 
    79     * process' life cycle, such as before and after process.destroy() gets called 
    80     */ 
     78    /** allow callers to implement hooks that get called during the main phases of the internal 
     79    * process' life cycle, such as before and after process.destroy() gets called 
     80     */ 
    8181    private MainProcessHandler mainHandler = null; 
    8282 
     
    127127 
    128128    /** to set a handler that will handle the main (SafeProcess) thread, 
    129     * implementing the hooks that will get called during the internal process' life cycle, 
     129    * implementing the hooks that will get called during the internal process' life cycle, 
    130130     * such as before and after process.destroy() is called */ 
    131131    public void setMainHandler(MainProcessHandler handler) { 
     
    152152    */ 
    153153 
     154 
    154155    /** 
    155      * Call this method when you want to prematurely and safely terminate any process 
    156      * that SafeProcess may be running. 
    157      * You may want to implement the SafeProcess.MainHandler interface to write code 
    158      * for any hooks that will get called during the process' life cycle. 
    159      * @return false if process has already terminated or if it was already terminating 
    160      * when cancel was called. In such cases no interrupt is sent. Returns boolean sentInterrupt. 
     156     * If calling this method from a GUI thread when the SafeProcess is in the uninterruptible 
     157     * phase of natural termination, then this method will return immediately before that phase 
     158     * has ended. To force the caller to wait until the natural termination phase has ended, 
     159     * call the other variant of this method with param forceWaitUntilInterruptible set to true: 
     160     * cancelRunningProcess(true). 
     161     * @return false if process has already terminated or if it was already terminating when 
     162     * cancel was called. In such cases no interrupt is sent. 
     163     * This method returns a boolean that you can call sentInterrupt.   
    161164     */ 
    162     public synchronized boolean cancelRunningProcess() { 
     165    public boolean cancelRunningProcess() {  
     166 
     167    boolean forceWaitUntilInterruptible = true; 
     168    // by default, event dispatch threads may not want to wait for any joins() taking 
     169    // place at the time of cancel to be completed. 
     170    // So don't wait until the SafeProcess becomes interruptible 
     171    return this.cancelRunningProcess(!forceWaitUntilInterruptible); 
     172    } 
     173 
     174    /** 
     175     * Call this method when you want to prematurely and safely terminate any process 
     176     * that SafeProcess may be running. 
     177     * You may want to implement the SafeProcess.MainHandler interface to write code 
     178     * for any hooks that will get called during the process' life cycle. 
     179     * @param forceWaitUntilInterruptible if set to true by a calling GUI thread, then this method 
     180     * won't return until the running process is interruptible, even if SafeProcess is in the phase 
     181     * of naturally terminating, upon which no interrupts will be sent to the SafeProcess 
     182     * thread anyway. The join() calls within SafeProcess.runProcess() are blocking calls and are 
     183     * therefore sensitive to InterruptedExceptions. But the join() calls are part of the cleanup 
     184     * phase and shouldn't be interrupted, and nothing thereafter can be interrupted anyway. 
     185     * This method tends to be called with the param set to false. In that case, if the SafeProcess 
     186     * is in an uninterruptible phase (as can then only happen during clean up of natural 
     187     * termination) then a calling GUI thread will just return immediately. Meaning, the GUI thread 
     188     * won't wait for the SafeProcess thread to finish cleaning up. 
     189     * @return false if process has already terminated or if it was already terminating when 
     190     * cancel was called. In such cases no interrupt is sent. 
     191     * This method returns a boolean that you can call sentInterrupt. 
     192     */ 
     193    public synchronized boolean cancelRunningProcess(boolean forceWaitUntilInterruptible) { 
    163194    // on interrupt: 
    164195    // - forciblyTerminate will be changed to true if the interrupt came in when the process was 
     
    182213    // have to wait until afterward      
    183214    if (interruptible) { 
    184         // either way, we can now interrupt the thread - if we have one (we should) 
    185         if(this.theProcessThread != null) { // we're told which thread should be interrupted 
     215        // either way, we can now interrupt the thread that SafeProcess.runProcess() is running in 
     216        if(this.theProcessThread != null) { // we stored a ref to the main thread that's to be interrupted 
    186217        this.theProcessThread.interrupt(); 
    187218        log("@@@ Successfully sent interrupt to process."); 
     
    189220        } 
    190221    } 
    191     else { // wait for join()s to finish. 
     222    else { // wait for join()s to finish, if we've been asked to wait 
     223         
    192224        // During and after joining(), there's no need to interrupt any more anyway: no calls 
    193         // subsequent to joins() block, so everything thereafter is insensitive to InterruptedExceptions. 
    194  
    195         if(SwingUtilities.isEventDispatchThread()) { 
     225        // subsequent to joins() block, so everything thereafter is insensitive to InterruptedExceptions 
     226        // and everything from the joins() onward are cleanup on natural process termination, so no 
     227        // interrupt is needed after the joins().  
     228        // Still, even if the caller is a GUI thread, they can decide if they want to wait until this 
     229        // method's end: until the SafeProcess becomes interruptible again 
     230 
     231        if(!forceWaitUntilInterruptible && SwingUtilities.isEventDispatchThread()) { 
    196232        log("#### Event Dispatch thread, returning"); 
    197233        return false; 
     
    757793// but the other suggestion did work: pkill -TERM -P pid did work 
    758794// More reading: 
     795// https://superuser.com/questions/343031/sigterm-with-a-keyboard-shortcut 
     796// Ctrl-C sends a SIGNINT, not SIGTERM or SIGKILL. And on Ctrl-C, "the signal is sent to the foreground *process group*." 
    759797// https://linux.die.net/man/1/kill (manual) 
    760798// https://unix.stackexchange.com/questions/117227/why-pidof-and-pgrep-are-behaving-differently 
     
    765803 
    766804/** 
    767  * On Unix, will kill the process denoted by processID and any subprocessed this launched. Tested on a Mac, where this is used. 
     805 * On Unix, will kill the process denoted by processID and any subprocesses this launched. Tested on a Mac, where this is used. 
    768806 * @param force if true will send the -KILL (-9) signal, which may result in abrupt termination without cleanup 
    769807 * if false, will send the -TERM (-15) signal, which will allow cleanup before termination. Sending a SIGTERM is preferred. 
     
    810848    // the process and its subprocesses (don't need to call this method at all to terminate the processes: the processes 
    811849    // aren't running when we get to this method) 
    812     log("@@@ Sending termination signal returned exit value 1. On unix this happens when the process has already been terminated."); 
     850    log("@@@ Sending termination signal returned exit value 1. On unix this can happen when the process has already been terminated."); 
    813851    return true; 
    814852    } else {