def close(self):
        """
        When this method is called, any callers blocking waiting for
        socket events will be released, and caused to throw a
        ``AsyncSocketMgrNotOpen`` exception. This call is synchronous,
        and will not return until all internal cleanup has been
        performed. Still, some waiters might end up throwing their
        exception only after this method returns, which is not
        a problem.

        (Only called by external threads.)
        """
        if self.dead:
            # Nothing to be done anymore.
            return

        try:
            if logging_enabled():
                logwrite("adding deathwish")
            self.wait_for_request(None, "die",
                                  self.mortally_wound_internal_thread, [])
            if logging_enabled():
                logwrite("deathwish acked")
        except AsyncSocketMgrNotOpen:
            # I guess someone else has already asked the manager
            # to stop accepting requests, which is fine.
            pass

        # This method may not return until cleanup is
        # complete, so do not.
        if logging_enabled():
            logwrite("waiting for internal death to die")
        while not self.dead:
            time.sleep(0.1)
    def wait_for_request(self, handle, req_type, req_func, req_args):
        """
        Has the internal thread execute the function ``req_func`` with
        the arguments in list ``req_args``, and returns any result
        that ``req_func`` delivers back to this thread (by placing it
        into a known container). If the result indicates an error,
        ``wait_for_request`` throws the exception provided by
        ``req_func``.
        
        Note that we do not need to "send" requests to the internal
        thread. All we do need to do is to add them into the internal
        queue, and ensure that the internal thread notices. This
        operation may fail, and if it does, ``wait_for_request``
        throws an exception.

        The ``handle`` argument specifies that the request concerns
        the socket with the particular handle. If the value is
        ``None``, then the request concerns an uncreated socket,
        or the manager itself.

        The ``req_type`` value is a descriptive string that is used
        mostly for more informative logging, but may in some special
        cases also otherwise affect the way a request gets processed.
        """
        if logging_enabled():
            logwrite("making a " + req_type + " request concerning " +
                     str(handle))

        blocker = EvSubst()
        result = []
        req = ["req", handle, req_type, req_func, req_args, blocker, result]

        self.mutex.acquire()
        try:
            # This may fail with an exception, which is fine.
            self.queue_add(req)
        finally:
            self.mutex.release()

        # Wait for the request to complete.
        if logging_enabled():
            logwrite("wait_for_request--waiting")
        blocker.wait()
        if logging_enabled():
            logwrite("wait_for_request--released")

        # Return (or throw) the result.
        assert len(result) == 1
        error_status, data = result[0]
        if error_status:
            raise error_status
        return data
    def close_all_managed_sockets(self):
        """
        Closes all the sockets being managed by this object.

        (Only called by the internal thread.)
        """
        if logging_enabled():
            logwrite("closing all managed sockets")
        for k, v in self.socket_map.iteritems():
            v.close()
        self.socket_map.clear()
    def process_request(self, req):
        """
        The ``req`` parameter specifies a request entry.
        It must be of the form
        ["req", handle, req_type, func, args, result, event]
        where

        * ``func`` is the function that processes the request

        * ``args`` is an array of arguments to pass to ``func``

        * ``result`` is empty array into which the result of the request
          will be stored in the form (status, retval), where

          * ``status`` is ``None``,
            or an exception in case of error completion

          * ``retval`` is a request specific result value
        
        * ``event`` is an ``Event`` object to signal when the request
          has been completed

        (Only called by the internal thread.)
        """
        func = req[3]
        args = req[4]
        try:
            if logging_enabled():
                logwrite("processing a " + req[2] + " request concerning " +
                         str(req[1]))
                logwrite("calling function " + str(func))
            func(self, req, *args)
            if logging_enabled():
                logwrite("called ok")
        except Exception, exc:
            if logging_enabled():
                logwrite("got exception")
                log_exception()
            self.complete_request(req, exc)
            if logging_enabled():
                logwrite("completed with error")
    def mortally_wound_internal_thread(self, dummy, req):
        """
        This call causes the internal thread to wrap things up and
        die. The internal thread should take note of this, and start
        dying. It does not need to be dead yet by the time it signals
        the request. Indeed, it cannot itself signal anything after it
        already is dead.

        (Only called by the internal thread.)
        """
        if not self.dying:
            # After this flag has been set, the internal thread
            # can no longer be assumed to handle or successfully
            # complete socket-related requests, as it won't
            # be processing socket events.
            self.dying = True
        if logging_enabled():
            logwrite("completing wounding request")
        self.complete_request(req)
        if logging_enabled():
            logwrite("completed wounding request")
        def listenfunc(self, req, handle, kw):
            def cbfunc(orig, evtype, evstat, payload, cbparams):
                self, req = cbparams
                if self.__check_state(req):
                    self.__mark_not_pending(req)
                    assert evtype == "listen"
                    if not evstat:
                        self.complete_request(req)
                    else:
                        self.complete_request(req, evstat)

            if self.__check_state(req):
                socket = self.socket_map[handle]
                if logging_enabled():
                    logwrite("listenfunc--calling listen on " + str(socket))
                socket.listen(cbfunc, (self, req), **kw)
                self.__mark_pending(req)
    def create_internal_thread(self):
        """
        This method creates and starts the internal thread that owns
        all the sockets, storing a reference to it in the internal
        ``thread`` property.
        """
        # Create the Symbian-specific instance of this.
        self.itc = SymbianItc()

        # Now create and start the thread.
        # Do not forget to store the thread ID.
        if logging_enabled():
            logwrite("starting internal thread")
        self.thread = None
        self.thread = start_thread(target=self.__loop,
                                   name="socket-owner-thread-%d" % hash(self),
                                   args=())
    def __loop(self):
        """
        The thread that owns all the sockets runs this loop that
        processes all asynchronous events, as well as decides how to
        handle any requests in the internal queue. To get this thread
        to do something for you (instead of blocking and waiting for
        events), simply queue a new asynchronous request for the
        thread to deal with.
        """
        try:
            if logging_enabled():
                logwrite("internal thread running")
                logwrite("logging enabled")

            # We use this value internally, too, so ensure it's set
            # before we do.
            while not self.thread:
                time.sleep(0.1)

            set_thread_priority(self.thread_pri)

            self.aoloop = AoLoop()
            self.aoloop.open()

            # Note that it is imperative that we _create_ active objects
            # within this thread, as otherwise they will get registered
            # with the active scheduler of some other thread, resulting
            # in stray signals when requests are made. We should also
            # note that some other thread may try to access the ``itc``
            # object already before this thread gets to run, which is
            # why we created the object earlier, but are only now
            # registering it with the active scheduler.
            self.immediate = AoImmediate()
            self.immediate.open()
            self.itc.open()

            # We do not use this in this class, but we assume all
            # subclassers need an instance of this for initializing
            # RSocket instances.
            if logging_enabled():
                logwrite("creating socket server handle")
            self.socket_serv = SymbianSocketServ()

            # Run a new active scheduler loop until someone
            # calls ``close``.
            self.immediate.complete(self.__req_init, None)
            if logging_enabled():
                logwrite("starting ao loop")
            self.aoloop.start()
            if logging_enabled():
                logwrite("ao loop exited")

            # This will cancel any remaining requests.
            self.__process_any_requests()

            # Now release those waiting for requests that we already
            # started processing.
            self.cancel_all_pending_requests()

            # This will ensure that no new socket-related events
            # will be generated, but some might have been generated
            # already, causing callbacks after all the cleanup
            # has already been done. We must make sure not to do
            # anything in such callbacks.
            self.close_all_managed_sockets()

            # Note that those objects that might have thread-specific
            # sessions must be cleaned up by this thread, rather
            # than left for GC to handle. We are doing the cleanup here.
            self.socket_serv.close()
            self.aoloop.close()
            self.immediate.close()
            self.itc.close()
            if logging_enabled():
                logwrite("stopping logging for internal thread")
            thread_finish_logging()

            # This thread should die any moment after this.
            self.dead = True
        except:
            # Does nothing if logging has been stopped already.
            log_exception()