Changeset 31703


Ignore:
Timestamp:
2017-05-25T18:47:14+12:00 (7 years ago)
Author:
ak19
Message:

When an instance of SafeProcess calls its static destroyProcess method, this happens on cancel action which would have caused an Interrupt to the SafeProcess thread that interrupts the worker threads, all of which cleanly tidy up after themselves. On Linux, this has the effect that the Process internal to SafeProcess, and any subprocesses that the process may have launched, are all neatly terminated. So on Linux, when destroyProcess is called by a SafeProcess instance on itself, there's no need to send a SIGTERM (else SIGKILL) to terminate the Process, as it's already cleanly terminated. Reducing the overkill step in such a scenario. The public static SafeProcess.destroyProcess(Process p) now forces the step of sending a termination signal, since any caller outside a SafeProcess instance won't neatly tidy up their Process object with interrupts.

File:
1 edited

Legend:

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

    r31702 r31703  
    609609
    610610        if(mainHandler != null) mainHandler.beforeProcessDestroy();
    611         SafeProcess.destroyProcess(process); // see runProcess(2 args/3 args)
     611        boolean noNeedToDestroyIfOnLinux = true; // Interrupt handling suffices to cleanup process and subprocesses on Linux
     612        SafeProcess.destroyProcess(process, noNeedToDestroyIfOnLinux); // see runProcess(2 args/3 args)
    612613        if(mainHandler != null) mainHandler.afterProcessDestroy();
    613614
     
    809810    // the process and its subprocesses (don't need to call this method at all to terminate the processes: the processes
    810811    // aren't running when we get to this method)
    811     log("@@@ Termination signal returned exitvalue 1, on linux this happens when the process has already been terminated");
     812    log("@@@ Sending termination signal returned exit value 1. On linux this happens when the process has already been terminated");
    812813    return true;
    813814    } else {
     
    820821}
    821822
     823public static void destroyProcess(Process p) {
     824    // A cancel action results in an interruption to the process thread, which in turn interrupts
     825    // the SafeProcess' worker threads, all which clean up after themselves.
     826    // On linux, this suffices to cleanly terminate a Process and any subprocesses that may have launched
     827    // so we don't need to do extra work in such a case. But the interrupts happen only when SafeProcess calls
     828    // destroyProcess() on the Process it was running internally, and not if anyone else tries to end a
     829    // Process by calling SafeProcess.destroyProcess(p). In such cases, the Process needs to be actively terminated:
     830    boolean canSkipExtraWorkIfLinux = true;
     831    SafeProcess.destroyProcess(p, !canSkipExtraWorkIfLinux);
     832}
    822833
    823834// On linux and mac, p.destroy() suffices to kill processes launched by p as well.
    824835// On Windows we need to do more work, since otherwise processes launched by p remain around executing until they naturally terminate.
    825836// e.g. full-import.pl may be terminated with p.destroy(), but it launches import.pl which is left running until it naturally terminates.
    826 public static void destroyProcess(Process p) {
     837private static void destroyProcess(Process p, boolean canSkipExtraWorkIfLinux) {
    827838    log("### in SafeProcess.destroyProcess(Process p)");
    828839
    829840    // If it isn't windows, process.destroy() terminates any child processes too
    830     if(!Utility.isWindows()) {
     841    if(Utility.isWindows()) {
     842   
     843    if(!SafeProcess.isAvailable("wmic")) {
     844        log("wmic, used to kill subprocesses, is not available. Unable to terminate subprocesses...");
     845        log("Kill them manually from the TaskManager or they will proceed to run to termination");
     846       
     847        // At least we can get rid of the top level process we launched
     848        p.destroy();
     849        return;
     850    }   
     851   
     852    // get the process id of the process we launched,
     853    // so we can use it to find the pids of any subprocesses it launched in order to terminate those too.
     854   
     855    long processID = SafeProcess.getProcessID(p);
     856    if(processID == -1) { // the process doesn't exist or no longer exists (terminated naturally?)
     857        p.destroy(); // minimum step, do this anyway, at worst there's no process and this won't have any effect
     858    } else {
     859        log("Attempting to terminate sub processes of Windows process with pid " + processID);
     860        terminateSubProcessesRecursively(processID, p);
     861    }
     862    return;
     863   
     864    }
     865    else { // linux or mac
     866
     867    // if we're on linux and would have already terminated by now (in which case canSkipExtraWorkForLinux would be true),
     868    // then there's nothing much left to do. This would only be the case if SafeProcess is calling this method on its
     869    // internal process, since it would have successfully cleaned up on Interruption and there would be no process left running
     870    if(!Utility.isMac() && canSkipExtraWorkIfLinux) {
     871        log("@@@ Linux: Cancelling a SafeProcess instance does not require any complicated system destroy operation");
     872        p.destroy(); // vestigial: this will have no effect if the process had already terminated, which is the case in this block
     873        return;
     874    }
     875    // else we're on a Mac or an external caller (not SafeProcess) has requested explicit termination on Linux
     876   
    831877    long pid = SafeProcess.getProcessID(p);
    832878    /*
     
    845891        }       
    846892    }
    847 
     893   
    848894    return;
    849895    }
     
    851897    // else we're on windows:
    852898
    853     if(!SafeProcess.isAvailable("wmic")) {
    854     log("wmic, used to kill subprocesses, is not available. Unable to terminate subprocesses...");
    855     log("Kill them manually from the TaskManager or they will proceed to run to termination");
    856    
    857     // At least we can get rid of the top level process we launched
    858     p.destroy();
    859     return;
    860     }   
    861    
    862     // get the process id of the process we launched,
    863     // so we can use it to find the pids of any subprocesses it launched in order to terminate those too.
    864    
    865     long processID = SafeProcess.getProcessID(p);
    866     if(processID == -1) { // the process doesn't exist or no longer exists (terminated naturally?)
    867     p.destroy(); // minimum step, do this anyway, at worst there's no process and this won't have any effect
    868     } else {
    869     log("Attempting to terminate sub processes of Windows process with pid " + processID);
    870     terminateSubProcessesRecursively(processID, p);
    871     }
    872899   
    873900}
Note: See TracChangeset for help on using the changeset viewer.