Show
Ignore:
Timestamp:
01/14/04 16:52:01 (20 years ago)
Author:
jalet
Message:

Small fix for job cancelling code.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r1289 r1291  
    2424# 
    2525# $Log$ 
     26# Revision 1.24  2004/01/14 15:52:01  jalet 
     27# Small fix for job cancelling code. 
     28# 
    2629# Revision 1.23  2004/01/13 10:48:28  jalet 
    2730# Small streams polling loop modification. 
     
    114117import select 
    115118import signal 
     119import time 
    116120 
    117121from pykota.tool import PyKotaFilterOrBackend, PyKotaToolError 
     
    120124from pykota.accounter import PyKotaAccounterError 
    121125from pykota.requester import PyKotaRequesterError 
    122  
    123 gotSigTerm = 0 
    124 def sigterm_handler(signum, frame) : 
    125     """Sets a global variable whenever SIGTERM is received.""" 
    126     # SIGTERM will be ignore most of the time, but during 
    127     # the call to the real backend, we have to pass it through. 
    128     global gotSigTerm 
    129     gotSigTerm = 1 
    130126     
    131127class PyKotaPopen3(popen2.Popen3) : 
     
    152148class PyKotaBackend(PyKotaFilterOrBackend) :         
    153149    """A class for the pykota backend.""" 
     150    def __init__(self) : 
     151        """Does normal initialization then installs signal handler.""" 
     152        # Normal init 
     153        PyKotaFilterOrBackend.__init__(self) 
     154         
     155        # then deal with signals 
     156        # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM 
     157        # Fortunately SIGPIPE is already ignored by Python 
     158        # It's there just in case this changes in the future. 
     159        # Here we have to handle SIGTERM correctly, and pass 
     160        # it to the original backend if needed. 
     161        self.gotSigTerm = 0 
     162        signal.signal(signal.SIGPIPE, signal.SIG_IGN) 
     163        signal.signal(signal.SIGTERM, self.sigterm_handler) 
     164         
     165    def sigterm_handler(self, signum, frame) : 
     166        """Sets a global variable whenever SIGTERM is received.""" 
     167        # SIGTERM will be ignore most of the time, but during 
     168        # the call to the real backend, we have to pass it through. 
     169        self.gotSigTerm = 1 
     170        self.logger.log_message(_("SIGTERM received, job %s cancelled.") % self.jobid, "info") 
     171         
    154172    def acceptJob(self) :         
    155173        """Returns the appropriate exit code to tell CUPS all is OK.""" 
     
    165183    def doWork(self, policy, printer, user, userpquota) :     
    166184        """Most of the work is done here.""" 
    167         global gotSigTerm 
    168185        # Two different values possible for policy here : 
    169186        # ALLOW means : Either printer, user or user print quota doesn't exist, 
     
    181198        # pass the job's data to the real backend     
    182199        if action in ["ALLOW", "WARN"] : 
    183             if gotSigTerm : 
     200            if self.gotSigTerm : 
    184201                retcode = self.removeJob() 
    185202            else :     
     
    211228        # Now it becomes tricky... 
    212229        # We must pass the unmodified job to the original backend 
    213          
    214         global gotSigTerm 
    215          
    216230        # First ensure that we have a file object as input 
    217231        mustclose = 0     
     
    256270        endinput = endoutput = enderr = 0 
    257271        inputclosed = outclosed = errclosed = 0 
     272        killed = 0 
    258273        self.logdebug("Entering streams polling loop...") 
    259274        status = -1 
     
    264279            # Now if we got SIGTERM, we have  
    265280            # to kill -TERM the original backend 
    266             if gotSigTerm : 
     281            if self.gotSigTerm and not killed : 
    267282                try : 
    268283                    os.kill(subprocess.pid, signal.SIGTERM) 
     284                    self.logger.log_message(_("SIGTERM was sent to real backend %s (pid: %s)") % (realbackend, subprocess.pid), "info") 
     285                    killed = 1 
    269286                except : # ignore if process was already killed. 
    270287                    pass 
     
    272289            # In any case, deal with any remaining I/O 
    273290            availablefds = pollster.poll(5000) 
    274             if (not availablefds) and inputclosed and outputclosed and errclosed : 
    275                 break 
    276291            for (fd, mask) in availablefds : 
    277292                # self.logdebug("file: %i    mask: %04x" % (fd, mask)) 
     
    284299                        if endinput :     
    285300                            pollster.unregister(tocfno)         
     301                            self.logdebug("Closing real backend's stdin.") 
    286302                            os.close(tocfno) 
    287                             self.logdebug("Closing real backend's stdin.") 
    288303                            inputclosed = 1 
    289304                    elif fd == stdoutfno : 
     
    331346                        # standard output. 
    332347                        # We are no more interested in this file descriptor         
     348                        self.logdebug("Closing real backend's stdout.") 
    333349                        os.close(fromcfno) 
    334                         self.logdebug("Real backend's stdout ends.") 
    335350                        endoutput = 1 
    336351                    elif fd == cerrfno :     
     
    338353                        # to write informations on its standard error. 
    339354                        # We are no more interested in this file descriptor        . 
     355                        self.logdebug("Closing real backend's stderr.") 
    340356                        os.close(cerrfno) 
    341                         self.logdebug("Real backend's stderr ends.") 
    342357                        enderr = 1 
     358            if killed or (inputclosed and outputclosed and errclosed) : 
     359                break 
    343360                 
     361        # We must close the real backend's input stream 
     362        if killed and not inputclosed : 
     363            self.logdebug("Forcing close of real backend's stdin.") 
     364            os.close(tocfno) 
     365         
    344366        # Input file was a real file, we have to close it.     
    345367        if mustclose : 
     
    351373        if os.WIFEXITED(status) : 
    352374            retcode = os.WEXITSTATUS(status) 
    353         else :     
     375        elif not killed :     
    354376            self.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 
    355377            retcode = -1 
     378        else :     
     379            retcode = self.removeJob() 
    356380        return retcode     
    357381     
    358382if __name__ == "__main__" :     
    359383    # This is a CUPS backend, we should act and die like a CUPS backend 
    360      
    361     # first deal with signals 
    362     # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM 
    363     # Fortunately SIGPIPE is already ignored by Python 
    364     # It's there just in case this changes in the future. 
    365     # Here we have to handle SIGTERM correctly, and pass 
    366     # it to the original backend if needed. 
    367     global gotSigTerm 
    368     gotSigTerm = 0 
    369     signal.signal(signal.SIGPIPE, signal.SIG_IGN) 
    370     signal.signal(signal.SIGTERM, sigterm_handler) 
    371      
    372384    if len(sys.argv) == 1 : 
    373385        # we will execute each existing backend in device enumeration mode