예제 #1
0
    def _watchFD(self, fd, descr, flag):
        """
        Register a file descriptor with the C{CFRunLoop}, or modify its state
        so that it's listening for both notifications (read and write) rather
        than just one; used to implement C{addReader} and C{addWriter}.

        @param fd: The file descriptor.

        @type fd: L{int}

        @param descr: the L{IReadDescriptor} or L{IWriteDescriptor}

        @param flag: the flag to register for callbacks on, either
            C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack}
        """
        if fd == -1:
            raise RuntimeError("Invalid file descriptor.")
        if fd in self._fdmap:
            src, cfs, gotdescr, rw = self._fdmap[fd]
            # do I need to verify that it's the same descr?
        else:
            ctx = []
            ctx.append(fd)
            cfs = CFSocketCreateWithNative(
                kCFAllocatorDefault,
                fd,
                kCFSocketReadCallBack
                | kCFSocketWriteCallBack
                | kCFSocketConnectCallBack,
                self._socketCallback,
                ctx,
            )
            CFSocketSetSocketFlags(
                cfs,
                kCFSocketAutomaticallyReenableReadCallBack
                | kCFSocketAutomaticallyReenableWriteCallBack
                |
                # This extra flag is to ensure that CF doesn't (destructively,
                # because destructively is the only way to do it) retrieve
                # SO_ERROR and thereby break twisted.internet.tcp.BaseClient,
                # which needs SO_ERROR to tell it whether or not it needs to
                # call connect_ex a second time.
                _preserveSOError,
            )
            src = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfs, 0)
            ctx.append(src)
            CFRunLoopAddSource(self._cfrunloop, src, kCFRunLoopCommonModes)
            CFSocketDisableCallBacks(
                cfs,
                kCFSocketReadCallBack
                | kCFSocketWriteCallBack
                | kCFSocketConnectCallBack,
            )
            rw = [False, False]
            self._idmap[id(descr)] = fd
            self._fdmap[fd] = src, cfs, descr, rw
        rw[self._flag2idx(flag)] = True
        CFSocketEnableCallBacks(cfs, flag)
예제 #2
0
    def register(self, fileobj, events, data=None):
        fileno = fileobj if isinstance(fileobj, int) else fileobj.fileno()
        key = SelectorKey(fileobj, fileno, events, data)
        self._mappings[fileobj] = key

        entry = _FDEntry()
        entry.cf_fd = CFFileDescriptorCreate(kCFAllocatorDefault, fileno, 0,
                                             self._fdCallback, key)
        self._fd_events_to_enable[entry.cf_fd] = events
        entry.cf_source = CFFileDescriptorCreateRunLoopSource(
            kCFAllocatorDefault, entry.cf_fd, 0)
        CFRunLoopAddSource(self._runloop, entry.cf_source,
                           kCFRunLoopCommonModes)
        self._registered_fds[fileobj] = entry
예제 #3
0
    def wait_for(self, notification=None, filter_=None, timeout=5):
        self.callback_result = None

        @PAXObserverCallback
        def _callback(observer, element, notification, refcon):
            logger.debug("CALLBACK")
            logger.debug("%s, %s, %s, %s" %
                         (observer, element, notification, refcon))
            ret_element = self.ref.__class__(element)
            if filter_(ret_element):
                self.callback_result = ret_element

        observer = PAXObserverCreate(self.ref.pid, _callback)

        PAXObserverAddNotification(observer, self.ref.ref, notification,
                                   id(self.ref.ref))

        # Add observer source to run loop
        CFRunLoopAddSource(
            CFRunLoopGetCurrent(),
            AXObserverGetRunLoopSource(observer),
            NSDefaultRunLoopMode,
        )

        def event_stopper():
            end_time = time.time() + timeout
            while time.time() < end_time:
                if self.callback_result is not None:
                    break
            AppHelper.callAfter(AppHelper.stopEventLoop)

        event_watcher = threading.Thread(target=event_stopper)
        event_watcher.daemon = True
        event_watcher.start()

        # Set the signal handlers prior to running the run loop
        oldSigIntHandler = MachSignals.signal(signal.SIGINT, _sigHandler)
        AppHelper.runConsoleEventLoop()
        MachSignals.signal(signal.SIGINT, oldSigIntHandler)

        PAXObserverRemoveNotification(observer, self.ref.ref, notification)

        return self.callback_result