Пример #1
0
    def close(self, immediate=False, expected=True):
        """
        Closes the channel.
        
        :param immediate: if False and there is data in the write buffer, the
                          channel is closed once the write buffer is emptied.
                          Otherwise the channel is closed immediately and the 
                          *closed* signal is emitted.
        :type immediate: bool
        """
        log.debug('IOChannel closed: channel=%s, immediate=%s, fd=%s', self, immediate, self.fileno)
        if not self._rmon and not self._wmon:
            # already closed
            return

        if not immediate and self._write_queue:
            # Immediate close not requested and we have some data left
            # to be written, so defer close until after write queue
            # is empty.
            self._queue_close = True
            return


        if self._rmon:
            self._rmon.unregister()
        if self._wmon:
            self._wmon.unregister()
        self._rmon = None
        self._wmon = None
        self._queue_close = False

        # Set _closing flag in case any callbacks connected to any pending
        # read/write InProgress objects test the 'alive' property, which we
        # want to be False.  Yet we don't want to actually _close() before
        # finishing the pending InProgress in case _close() raises, which
        # we want to let propagate.
        self._closing = True

        # Finish any InProgress waiting on read() or readline() with whatever
        # is left in the read queue.
        s = self._read_queue.getvalue()
        self._read_signal.emit(s)
        self._readline_signal.emit(s)
        self._clear_read_queue()

        # Throw IOError to any pending InProgress in the write queue
        for data, inprogress in self._write_queue:
            if len(inprogress):
                # Somebody cares about this InProgress, so we need to finish
                # it.
                inprogress.throw(IOError, IOError(9, 'Channel closed prematurely'), None)
        del self._write_queue[:]

        try:
            self._close()
        except (IOError, socket.error), (errno, msg):
            # Channel may already be closed, which is ok.
            if errno != 9:
                # It isn't, this is some other error, so reraise exception.
                raise
Пример #2
0
Файл: io.py Проект: clones/kaa
    def _handle_write(self):
        """
        IOMonitor callback when the channel is writable.  This callback is not
        registered then the write queue is empty, so we only get called when
        there is something to write.
        """
        if not self._write_queue:
            # Can happen if a write was aborted.
            return

        try:
            while self._write_queue:
                data, inprogress = self._write_queue.pop(0)
                sent = self._write(data)
                log.debug2('IOChannel write data: channel=%s fd=%s len=%d (of %d)', 
                           self._channel, self.fileno, sent, len(data))
                if sent != len(data):
                    # Not all data was able to be sent; push remaining data
                    # back onto the write buffer.
                    self._write_queue.insert(0, (data[(sent if sent >= 0 else 0):], inprogress))
                    break
                else:
                    # All data is written, finish the InProgress associated
                    # with this write.
                    inprogress.finish(sent)

            if not self._write_queue:
                if self._queue_close:
                    return self.close(immediate=True)
                self._wmon.unregister()

        except Exception, e:
            tp, exc, tb = sys.exc_info()
            if tp in (OSError, IOError, socket.error) and e.args[0] == 11:
                # Resource temporarily unavailable -- we are trying to write
                # data to a socket which is not ready.  To prevent a busy loop
                # (mainloop will keep calling us back) we sleep a tiny
                # bit.  It's admittedly a bit kludgy, but it's a simple
                # solution to a condition which should not occur often.
                self._write_queue.insert(0, (data, inprogress))
                time.sleep(0.001)
                return

            if tp in (IOError, socket.error, OSError):
                # Any of these are treated as fatal.  We close, which
                # also throws to any other pending InProgress writes.
                self.close(immediate=True, expected=False)
                # Normalize exception into an IOError.
                tp, exc = IOError, IOError(*e.args)
    
            # Throw the current exception to the InProgress for this write.
            # If nobody is listening for it, it will eventually get logged
            # as unhandled.
            inprogress.throw(tp, exc, tb)

            # XXX: this seems to be necessary in order to get the unhandled
            # InProgress to log, but I've no idea why.
            del inprogress
Пример #3
0
    def _handle_write(self):
        """
        IOMonitor callback when the channel is writable.  This callback is not
        registered then the write queue is empty, so we only get called when
        there is something to write.
        """
        if not self._write_queue:
            # Can happen if a write was aborted.
            return

        try:
            while self._write_queue:
                data, inprogress = self._write_queue.pop(0)
                sent = self._write(data)
                log.debug2('IOChannel write data: channel=%s fd=%s len=%d (of %d)', 
                           self._channel, self.fileno, sent, len(data))
                if sent != len(data):
                    # Not all data was able to be sent; push remaining data
                    # back onto the write buffer.
                    self._write_queue.insert(0, (data[(sent if sent >= 0 else 0):], inprogress))
                    break
                else:
                    # All data is written, finish the InProgress associated
                    # with this write.
                    inprogress.finish(sent)

            if not self._write_queue:
                if self._queue_close:
                    return self.close(immediate=True)
                self._wmon.unregister()

        except Exception, e:
            tp, exc, tb = sys.exc_info()
            if tp in (OSError, IOError, socket.error) and e.args[0] == 11:
                # Resource temporarily unavailable -- we are trying to write
                # data to a socket which is not ready.  To prevent a busy loop
                # (mainloop will keep calling us back) we sleep a tiny
                # bit.  It's admittedly a bit kludgy, but it's a simple
                # solution to a condition which should not occur often.
                self._write_queue.insert(0, (data, inprogress))
                time.sleep(0.001)
                return

            if tp in (IOError, socket.error, OSError):
                # Any of these are treated as fatal.  We close, which
                # also throws to any other pending InProgress writes.
                self.close(immediate=True, expected=False)
                # Normalize exception into an IOError.
                tp, exc = IOError, IOError(*e.args)
    
            # Throw the current exception to the InProgress for this write.
            # If nobody is listening for it, it will eventually get logged
            # as unhandled.
            inprogress.throw(tp, exc, tb)

            # XXX: this seems to be necessary in order to get the unhandled
            # InProgress to log, but I've no idea why.
            del inprogress