    """Used by the AsyncThreadedAppServer module.

    This file implements an object that can force a call to select in the main
    asyncore.poll loop to return. This dispatcher is added to the asyncore polling
    group. It is polled for reads. We make this object available to everyone.
    When we need the asyncore select loop to return, i.e., we have some data ready
    to go, we call the release() method, which does a quick write to it's own socket/file-descriptor. This causes select to return.

    """

    import asyncore
    import asynchat

    import os
    import socket
    import string
    import thread

    if os.name == 'posix':

        class SelectRelease (asyncore.file_dispatcher):
            """Version for Posix.

            In a Posix environment, we can use a file descriptor as the object
            that we include in the polling loop that we force a read on.

            """

            def __init__ (self):
                r, w = os.pipe()
                self.wpipe = w
                asyncore.file_dispatcher.__init__ (self, r)

            def readable (self):
                return 1

            def writable (self):
                return 0

            def handle_connect (self):
                pass

            def release (self):
                os.write (self.wpipe, 'x')

            def handle_read (self):
                self.recv (8192)

            def log(self,message):
                pass

    else:

        class SelectRelease (asyncore.dispatcher):
            """Version for MS Windows.

            Windows can't handle file descriptors in a select poll, so a real
            socket has to be used. This method was adapted from a similar module
            in the Zope Medusa server.

            """

            address = ('127.9.9.9', 19999)

            def __init__ (self):
                a = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
                w = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

                w.setsockopt(socket.IPPROTO_TCP, 1, 1)

                # get a pair of connected sockets
                host='127.9.9.9'
                port=19999
                while 1:
                    try:
                        self.address=(host, port)
                        a.bind(self.address)
                        break
                    except:
                        if port <= 19950:
                            raise 'Bind Error', 'Cannot bind trigger!'
                        port=port - 1

                a.listen (1)
                w.setblocking (0)
                try:
                    w.connect (self.address)
                except:
                    pass
                r, addr = a.accept()
                a.close()
                w.setblocking (1)
                self.trigger = w

                asyncore.dispatcher.__init__ (self, r)
                self._trigger_connected = 0

            def __repr__ (self):
                return '<select-trigger (loopback) at %x>' % id(self)

            def readable (self):
                return 1

            def writable (self):
                return 0

            def handle_connect (self):
                pass

            def release (self, thunk=None):
                self.trigger.send ('x')

            def handle_read (self):
                self.recv (8192)

            def log(self, message):
                pass