Exemple #1
0
	def doWaitForMultipleEvents(self, timeout):
		log.msg(channel='system', event='iteration', reactor=self)
		if timeout is None:
			#timeout = INFINITE
			timeout = 100
		else:
			timeout = int(timeout * 1000)

		if not (self._events or self._writes):
			# sleep so we don't suck up CPU time
			time.sleep(timeout / 1000.0)
			return

		canDoMoreWrites = 0
		for fd in self._writes.keys():
			if log.callWithLogger(fd, self._runWrite, fd):
				canDoMoreWrites = 1

		if canDoMoreWrites:
			timeout = 0

		handles = self._events.keys() or [self.dummyEvent]
		val = MsgWaitForMultipleObjects(handles, 0, timeout, QS_ALLINPUT | QS_ALLEVENTS)
		if val == WAIT_TIMEOUT:
			return
		elif val == WAIT_OBJECT_0 + len(handles):
			exit = win32gui.PumpWaitingMessages()
			if exit:
				self.callLater(0, self.stop)
				return
		elif val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles):
			fd, action = self._events[handles[val - WAIT_OBJECT_0]]
			log.callWithLogger(fd, self._runAction, action, fd)
Exemple #2
0
	def disconnectAll(self):
		"""Disconnect every reader, and writer in the system.
		"""
		selectables = self.removeAll()
		for reader in selectables:
			log.callWithLogger(reader,
							   reader.connectionLost,
							   failure.Failure(main.CONNECTION_LOST))
Exemple #3
0
	def doIteration(self, timeout):
		# This function sits and waits for an IO completion event.
		#
		# There are two requirements: process IO events as soon as they arrive
		# and process ctrl-break from the user in a reasonable amount of time.
		#
		# There are three kinds of waiting.
		# 1) GetQueuedCompletionStatus (self.port.getEvent) to wait for IO
		# events only.
		# 2) Msg* family of wait functions that can stop waiting when
		# ctrl-break is detected (then, I think, Python converts it into a
		# KeyboardInterrupt)
		# 3) *Ex family of wait functions that put the thread into an
		# "alertable" wait state which is supposedly triggered by IO completion
		#
		# 2) and 3) can be combined. Trouble is, my IO completion is not
		# causing 3) to trigger, possibly because I do not use an IO completion
		# callback. Windows is weird.
		# There are two ways to handle this. I could use MsgWaitForSingleObject
		# here and GetQueuedCompletionStatus in a thread. Or I could poll with
		# a reasonable interval. Guess what! Threads are hard.

		processed_events = 0
		if timeout is None:
			timeout = MAX_TIMEOUT
		else:
			timeout = min(MAX_TIMEOUT, int(1000*timeout))
		rc, bytes, key, evt = self.port.getEvent(timeout)
		while processed_events < EVENTS_PER_LOOP:
			if rc == WAIT_TIMEOUT:
				break
			if key != KEY_WAKEUP:
				assert key == KEY_NORMAL
				if not evt.ignore:
					log.callWithLogger(evt.owner, self._callEventCallback,
									   rc, bytes, evt)
					processed_events += 1
			rc, bytes, key, evt = self.port.getEvent(0)
Exemple #4
0
    def doIteration(self, timeout):
        # This function sits and waits for an IO completion event.
        #
        # There are two requirements: process IO events as soon as they arrive
        # and process ctrl-break from the user in a reasonable amount of time.
        #
        # There are three kinds of waiting.
        # 1) GetQueuedCompletionStatus (self.port.getEvent) to wait for IO
        # events only.
        # 2) Msg* family of wait functions that can stop waiting when
        # ctrl-break is detected (then, I think, Python converts it into a
        # KeyboardInterrupt)
        # 3) *Ex family of wait functions that put the thread into an
        # "alertable" wait state which is supposedly triggered by IO completion
        #
        # 2) and 3) can be combined. Trouble is, my IO completion is not
        # causing 3) to trigger, possibly because I do not use an IO completion
        # callback. Windows is weird.
        # There are two ways to handle this. I could use MsgWaitForSingleObject
        # here and GetQueuedCompletionStatus in a thread. Or I could poll with
        # a reasonable interval. Guess what! Threads are hard.

        processed_events = 0
        if timeout is None:
            timeout = MAX_TIMEOUT
        else:
            timeout = min(MAX_TIMEOUT, int(1000 * timeout))
        rc, bytes, key, evt = self.port.getEvent(timeout)
        while processed_events < EVENTS_PER_LOOP:
            if rc == WAIT_TIMEOUT:
                break
            if key != KEY_WAKEUP:
                assert key == KEY_NORMAL
                if not evt.ignore:
                    log.callWithLogger(evt.owner, self._callEventCallback, rc,
                                       bytes, evt)
                    processed_events += 1
            rc, bytes, key, evt = self.port.getEvent(0)
Exemple #5
0
	def callback(self, source, condition):
		log.callWithLogger(source, self._readAndWrite, source, condition)
		self.simulate() # fire Twisted timers
		return 1 # 1=don't auto-remove the source
Exemple #6
0
class KQueueReactor(posixbase.PosixReactorBase):
    """
	A reactor that uses kqueue(2)/kevent(2).

	@ivar _kq: A L{kqueue} which will be used to check for I/O readiness.

	@ivar _selectables: A dictionary mapping integer file descriptors to
		instances of L{FileDescriptor} which have been registered with the
		reactor.  All L{FileDescriptors} which are currently receiving read or
		write readiness notifications will be present as values in this
		dictionary.

	@ivar _reads: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_kq} for read readiness notifications which will be
		dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.

	@ivar _writes: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_kq} for write readiness notifications which will be
		dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.
	"""
    implements(IReactorFDSet)

    def __init__(self):
        """
		Initialize kqueue object, file descriptor tracking dictionaries, and the
		base class.
		"""
        self._kq = kqueue()
        self._reads = {}
        self._writes = {}
        self._selectables = {}
        posixbase.PosixReactorBase.__init__(self)

    def _updateRegistration(self, *args):
        self._kq.kevent([kevent(*args)], 0, 0)

    def addReader(self, reader):
        """Add a FileDescriptor for notification of data available to read.
		"""
        fd = reader.fileno()
        if fd not in self._reads:
            self._selectables[fd] = reader
            self._reads[fd] = 1
            self._updateRegistration(fd, EVFILT_READ, EV_ADD)

    def addWriter(self, writer):
        """Add a FileDescriptor for notification of data available to write.
		"""
        fd = writer.fileno()
        if fd not in self._writes:
            self._selectables[fd] = writer
            self._writes[fd] = 1
            self._updateRegistration(fd, EVFILT_WRITE, EV_ADD)

    def removeReader(self, reader):
        """Remove a Selectable for notification of data available to read.
		"""
        fd = reader.fileno()
        if fd in self._reads:
            del self._reads[fd]
            if fd not in self._writes:
                del self._selectables[fd]
            self._updateRegistration(fd, EVFILT_READ, EV_DELETE)

    def removeWriter(self, writer):
        """Remove a Selectable for notification of data available to write.
		"""
        fd = writer.fileno()
        if fd in self._writes:
            del self._writes[fd]
            if fd not in self._reads:
                del self._selectables[fd]
            self._updateRegistration(fd, EVFILT_WRITE, EV_DELETE)

    def removeAll(self):
        """
		Remove all selectables, and return a list of them.
		"""
        return self._removeAll([self._selectables[fd] for fd in self._reads],
                               [self._selectables[fd] for fd in self._writes])

    def getReaders(self):
        return [self._selectables[fd] for fd in self._reads]

    def getWriters(self):
        return [self._selectables[fd] for fd in self._writes]

    def doKEvent(self, timeout):
        """Poll the kqueue for new events."""
        if timeout is None:
            timeout = 1000
        else:
            timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            l = self._kq.kevent([], len(self._selectables), timeout)
        except OSError, e:
            if e[0] == errno.EINTR:
                return
            else:
                raise
        _drdw = self._doWriteOrRead
        for event in l:
            why = None
            fd, filter = event.ident, event.filter
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            log.callWithLogger(selectable, _drdw, selectable, fd, filter)
Exemple #7
0
class EPollReactor(posixbase.PosixReactorBase):
    """
	A reactor that uses epoll(4).

	@ivar _poller: A L{poll} which will be used to check for I/O
		readiness.

	@ivar _selectables: A dictionary mapping integer file descriptors to
		instances of L{FileDescriptor} which have been registered with the
		reactor.  All L{FileDescriptors} which are currently receiving read or
		write readiness notifications will be present as values in this
		dictionary.

	@ivar _reads: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_poller} for read readiness notifications which will
		be dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.

	@ivar _writes: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_poller} for write readiness notifications which will
		be dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.
	"""
    implements(IReactorFDSet)

    def __init__(self):
        """
		Initialize epoll object, file descriptor tracking dictionaries, and the
		base class.
		"""
        # Create the poller we're going to use.  The 1024 here is just a hint
        # to the kernel, it is not a hard maximum.
        self._poller = _epoll.epoll(1024)
        self._reads = {}
        self._writes = {}
        self._selectables = {}
        posixbase.PosixReactorBase.__init__(self)

    def _add(self, xer, primary, other, selectables, event, antievent):
        """
		Private method for adding a descriptor from the event loop.

		It takes care of adding it if  new or modifying it if already added
		for another state (read -> read/write for example).
		"""
        fd = xer.fileno()
        if fd not in primary:
            cmd = _epoll.CTL_ADD
            flags = event
            if fd in other:
                flags |= antievent
                cmd = _epoll.CTL_MOD
            # epoll_ctl can raise all kinds of IOErrors, and every one
            # indicates a bug either in the reactor or application-code.
            # Let them all through so someone sees a traceback and fixes
            # something.  We'll do the same thing for every other call to
            # this method in this file.
            self._poller._control(cmd, fd, flags)

            # Update our own tracking state *only* after the epoll call has
            # succeeded.  Otherwise we may get out of sync.
            primary[fd] = 1
            selectables[fd] = xer

    def addReader(self, reader):
        """
		Add a FileDescriptor for notification of data available to read.
		"""
        self._add(reader, self._reads, self._writes, self._selectables,
                  _epoll.IN, _epoll.OUT)

    def addWriter(self, writer):
        """
		Add a FileDescriptor for notification of data available to write.
		"""
        self._add(writer, self._writes, self._reads, self._selectables,
                  _epoll.OUT, _epoll.IN)

    def _remove(self, xer, primary, other, selectables, event, antievent):
        """
		Private method for removing a descriptor from the event loop.

		It does the inverse job of _add, and also add a check in case of the fd
		has gone away.
		"""
        fd = xer.fileno()
        if fd == -1:
            for fd, fdes in selectables.items():
                if xer is fdes:
                    break
            else:
                return
        if fd in primary:
            cmd = _epoll.CTL_DEL
            flags = event
            if fd in other:
                flags = antievent
                cmd = _epoll.CTL_MOD
            else:
                del selectables[fd]
            del primary[fd]
            # See comment above _control call in _add.
            self._poller._control(cmd, fd, flags)

    def removeReader(self, reader):
        """
		Remove a Selectable for notification of data available to read.
		"""
        self._remove(reader, self._reads, self._writes, self._selectables,
                     _epoll.IN, _epoll.OUT)

    def removeWriter(self, writer):
        """
		Remove a Selectable for notification of data available to write.
		"""
        self._remove(writer, self._writes, self._reads, self._selectables,
                     _epoll.OUT, _epoll.IN)

    def removeAll(self):
        """
		Remove all selectables, and return a list of them.
		"""
        return self._removeAll([self._selectables[fd] for fd in self._reads],
                               [self._selectables[fd] for fd in self._writes])

    def getReaders(self):
        return [self._selectables[fd] for fd in self._reads]

    def getWriters(self):
        return [self._selectables[fd] for fd in self._writes]

    def doPoll(self, timeout):
        """
		Poll the poller for new events.
		"""
        if timeout is None:
            timeout = 1
        timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            # Limit the number of events to the number of io objects we're
            # currently tracking (because that's maybe a good heuristic) and
            # the amount of time we block to the value specified by our
            # caller.
            l = self._poller.wait(len(self._selectables), timeout)
        except IOError, err:
            if err.errno == errno.EINTR:
                return
            # See epoll_wait(2) for documentation on the other conditions
            # under which this can fail.  They can only be due to a serious
            # programming error on our part, so let's just announce them
            # loudly.
            raise

        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = self._selectables[fd]
            except KeyError:
                pass
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)
Exemple #8
0
	def callback(self, source, condition):
		log.callWithLogger(source, self._doReadOrWrite, source, condition)
		self.simulate() # fire Twisted timers
		return 1 # 1=don't auto-remove the source
Exemple #9
0
class PollReactor(posixbase.PosixReactorBase):
	"""
	A reactor that uses poll(2).

	@ivar _poller: A L{poll} which will be used to check for I/O
		readiness.

	@ivar _selectables: A dictionary mapping integer file descriptors to
		instances of L{FileDescriptor} which have been registered with the
		reactor.  All L{FileDescriptors} which are currently receiving read or
		write readiness notifications will be present as values in this
		dictionary.

	@ivar _reads: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_poller} for read readiness notifications which will
		be dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.

	@ivar _writes: A dictionary mapping integer file descriptors to arbitrary
		values (this is essentially a set).  Keys in this dictionary will be
		registered with C{_poller} for write readiness notifications which will
		be dispatched to the corresponding L{FileDescriptor} instances in
		C{_selectables}.
	"""
	implements(IReactorFDSet)

	def __init__(self):
		"""
		Initialize polling object, file descriptor tracking dictionaries, and
		the base class.
		"""
		self._poller = poll()
		self._selectables = {}
		self._reads = {}
		self._writes = {}
		posixbase.PosixReactorBase.__init__(self)


	def _updateRegistration(self, fd):
		"""Register/unregister an fd with the poller."""
		try:
			self._poller.unregister(fd)
		except KeyError:
			pass

		mask = 0
		if fd in self._reads:
			mask = mask | POLLIN
		if fd in self._writes:
			mask = mask | POLLOUT
		if mask != 0:
			self._poller.register(fd, mask)
		else:
			if fd in self._selectables:
				del self._selectables[fd]

	def _dictRemove(self, selectable, mdict):
		try:
			# the easy way
			fd = selectable.fileno()
			# make sure the fd is actually real.  In some situations we can get
			# -1 here.
			mdict[fd]
		except:
			# the hard way: necessary because fileno() may disappear at any
			# moment, thanks to python's underlying sockets impl
			for fd, fdes in self._selectables.items():
				if selectable is fdes:
					break
			else:
				# Hmm, maybe not the right course of action?  This method can't
				# fail, because it happens inside error detection...
				return
		if fd in mdict:
			del mdict[fd]
			self._updateRegistration(fd)

	def addReader(self, reader):
		"""Add a FileDescriptor for notification of data available to read.
		"""
		fd = reader.fileno()
		if fd not in self._reads:
			self._selectables[fd] = reader
			self._reads[fd] =  1
			self._updateRegistration(fd)

	def addWriter(self, writer):
		"""Add a FileDescriptor for notification of data available to write.
		"""
		fd = writer.fileno()
		if fd not in self._writes:
			self._selectables[fd] = writer
			self._writes[fd] =  1
			self._updateRegistration(fd)

	def removeReader(self, reader):
		"""Remove a Selectable for notification of data available to read.
		"""
		return self._dictRemove(reader, self._reads)

	def removeWriter(self, writer):
		"""Remove a Selectable for notification of data available to write.
		"""
		return self._dictRemove(writer, self._writes)

	def removeAll(self):
		"""
		Remove all selectables, and return a list of them.
		"""
		return self._removeAll(
			[self._selectables[fd] for fd in self._reads],
			[self._selectables[fd] for fd in self._writes])


	def doPoll(self, timeout):
		"""Poll the poller for new events."""
		if timeout is not None:
			timeout = int(timeout * 1000) # convert seconds to milliseconds

		try:
			l = self._poller.poll(timeout)
		except SelectError, e:
			if e[0] == errno.EINTR:
				return
			else:
				raise
		_drdw = self._doReadOrWrite
		for fd, event in l:
			try:
				selectable = self._selectables[fd]
			except KeyError:
				# Handles the infrequent case where one selectable's
				# handler disconnects another.
				continue
			log.callWithLogger(selectable, _drdw, selectable, fd, event)
Exemple #10
0
    def disconnectAll(self):
        """Disconnect every reader, and writer in the system.
		"""
        selectables = self.removeAll()
        for reader in selectables:
            log.callWithLogger(reader, reader.connectionLost, failure.Failure(main.CONNECTION_LOST))