コード例 #1
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
コード例 #2
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
コード例 #3
0
ファイル: io.py プロジェクト: clones/kaa
    def write(self, data):
        """
        Writes the given data to the channel.
        
        :param data: the data to be written to the channel.
        :type data: string

        :returns: An :class:`~kaa.InProgress` object which is finished when the
                  given data is fully written to the channel.  The InProgress
                  is finished with the number of bytes sent in the last write 
                  required to commit the given data to the channel.  (This may
                  not be the actual number of bytes of the given data.)

                  If the channel closes unexpectedly before the data was
                  written, an IOError is thrown to the InProgress.

        It is not required that the channel be open in order to write to it.
        Written data is queued until the channel open and then flushed.  As
        writes are asynchronous, all written data is queued.  It is the
        caller's responsibility to ensure the internal write queue does not
        exceed the desired size by waiting for past write() InProgress to
        finish before writing more data.

        If a write does not complete because the channel was closed
        prematurely, an IOError is thrown to the InProgress.
        """
        if not (self._mode & IO_WRITE):
            raise IOError(9, 'Cannot write to a read-only channel')
        if not self.writable:
            raise IOError(9, 'Channel is not writable')
        if self.write_queue_used + len(data) > self._queue_size:
            raise ValueError('Data would exceed write queue limit')

        inprogress = InProgress()
        if data:
            def abort(exc):
                try:
                    self._write_queue.remove((data, inprogress))
                except ValueError:
                    # Too late to abort.
                    return False
            inprogress.signals['abort'].connect(abort)
            self._write_queue.append((data, inprogress))
            if self._channel and self._wmon and not self._wmon.active:
                self._wmon.register(self.fileno, IO_WRITE)
        else:
            # We're writing the null string, nothing really to do.  We're
            # implicitly done.
            inprogress.finish(0)
        return inprogress