def _unwatchFD(self, fd, descr, flag): """ Unregister a file descriptor with the C{CFRunLoop}, or modify its state so that it's listening for only one notification (read or write) as opposed to both; used to implement C{removeReader} and C{removeWriter}. @param fd: a file descriptor @type fd: C{int} @param descr: an L{IReadDescriptor} or L{IWriteDescriptor} @param flag: C{kCFSocketWriteCallBack} C{kCFSocketReadCallBack} """ if id(descr) not in self._idmap: return if fd == -1: # need to deal with it in this case, I think. realfd = self._idmap[id(descr)] else: realfd = fd src, cfs, descr, rw = self._fdmap[realfd] CFSocketDisableCallBacks(cfs, flag) rw[self._flag2idx(flag)] = False if not rw[_READ] and not rw[_WRITE]: del self._idmap[id(descr)] del self._fdmap[realfd] CFRunLoopRemoveSource(self._cfrunloop, src, kCFRunLoopCommonModes) CFSocketInvalidate(cfs)
def _socketCallback( self, cfSocket, callbackType, ignoredAddress, ignoredData, context ): """ The socket callback issued by CFRunLoop. This will issue C{doRead} or C{doWrite} calls to the L{IReadDescriptor} and L{IWriteDescriptor} registered with the file descriptor that we are being notified of. @param cfSocket: The C{CFSocket} which has got some activity. @param callbackType: The type of activity that we are being notified of. Either C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack}. @param ignoredAddress: Unused, because this is not used for either of the callback types we register for. @param ignoredData: Unused, because this is not used for either of the callback types we register for. @param context: The data associated with this callback by C{CFSocketCreateWithNative} (in C{CFReactor._watchFD}). A 2-tuple of C{(int, CFRunLoopSource)}. """ (fd, smugglesrc) = context if fd not in self._fdmap: # Spurious notifications seem to be generated sometimes if you # CFSocketDisableCallBacks in the middle of an event. I don't know # about this FD, any more, so let's get rid of it. CFRunLoopRemoveSource(self._cfrunloop, smugglesrc, kCFRunLoopCommonModes) return src, skt, readWriteDescriptor, rw = self._fdmap[fd] def _drdw(): why = None isRead = False try: if readWriteDescriptor.fileno() == -1: why = _NO_FILEDESC else: isRead = callbackType == kCFSocketReadCallBack # CFSocket seems to deliver duplicate read/write # notifications sometimes, especially a duplicate # writability notification when first registering the # socket. This bears further investigation, since I may # have been mis-interpreting the behavior I was seeing. # (Running the full Twisted test suite, while thorough, is # not always entirely clear.) Until this has been more # thoroughly investigated , we consult our own # reading/writing state flags to determine whether we # should actually attempt a doRead/doWrite first. -glyph if isRead: if rw[_READ]: why = readWriteDescriptor.doRead() else: if rw[_WRITE]: why = readWriteDescriptor.doWrite() except BaseException: why = sys.exc_info()[1] log.err() if why: self._disconnectSelectable(readWriteDescriptor, why, isRead) log.callWithLogger(readWriteDescriptor, _drdw)
def unregister(self, fileobj): del self._mappings[fileobj] source = self._registered_fds.pop(fileobj).cf_source CFRunLoopRemoveSource(self._runloop, source, kCFRunLoopCommonModes)