def worker(self): self.logger.debug("Opened tail stream on file {0} ({1} lines)".format(self.path, self.backlog)) with io.open(self.fd, "wb") as fd: with open(self.path, "rb") as f: kq = select.kqueue() try: ev = [ select.kevent( fd.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE ), select.kevent( f.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE ), ] fd.write(self.tail(f, self.backlog)) fd.flush() kq.control(ev, 0) f.seek(0, os.SEEK_END) while True: event, = kq.control(None, 1) self.logger.debug("kqueue event {0}".format(event)) if event.ident == fd.fileno(): if event.flags & select.KQ_EV_EOF or event.flags & select.KQ_EV_ERROR: break if event.ident == f.fileno(): fd.write(f.read()) fd.flush() finally: kq.close()
def modify(self, fd, read=True, write=True, error=True): """ Modify a file descriptor already registered in the kqueue to change the events being monitored. """ kevents = [] add_flags = select.KQ_EV_ADD if self._edge_triggered: add_flags = add_flags | select.KQ_EV_CLEAR if read and not fd in self._read_fds: kevents.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=add_flags)) self._read_fds.add(fd) elif not read and fd in self._read_fds: kevents.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) self._read_fds.discard(fd) if write and not fd in self._write_fds: kevents.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=add_flags)) self._write_fds.add(fd) elif not write and fd in self._write_fds: kevents.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) self._write_fds.discard(fd) if error: self._error_fds.add(fd) else: self._error_fds.discard(fd) for kevent in kevents: self._kqueue.control([kevent], 0)
def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('0.0.0.0', 5555)) server_socket.listen(5) kq = select.kqueue() kq.control([select.kevent(server_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD)], 0, 0) connections = {} while True: events = kq.control([], 10000) for event in events: if server_socket.fileno() == event.ident: (client_socket, client_address) = server_socket.accept() print 'got connection from', client_address kq.control([select.kevent(client_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD)], 0, 0) connections[client_socket.fileno()] = client_socket elif event.filter == select.KQ_FILTER_READ: client_socket = connections[event.ident] data = client_socket.recv(4096) if data: client_socket.send(data) else: kq.control( [select.kevent(client_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0, 0) client_socket.close() connections.pop(event.ident)
def del_channel(self, map=None): fd = self._fileno if map is None: map = self._map if fd in map: #self.log_info('closing channel %d:%s' % (fd, self)) del map[fd] if self._fileno: try: kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: epoll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no epoll used, or not registered pass try: poll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no poll used, or not registered pass self._fileno = None self.poller_flags = 0 self.poller_filter = 0 self.poller_registered = False
def _update_registration(self, fd, from_mask, to_mask): if from_mask == to_mask: return xor = from_mask ^ to_mask to_add = to_mask & xor to_drop = from_mask & xor assert not to_add & to_drop # simple sanity events = [] if to_add & self.INMASK: events.append(select.kevent( fd, select.KQ_FILTER_READ, select.KQ_EV_ADD)) elif to_drop & self.INMASK: events.append(select.kevent( fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)) if to_add & self.OUTMASK: events.append(select.kevent( fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD)) elif to_drop & self.OUTMASK: events.append(select.kevent( fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)) if events: if sys.platform == 'darwin': # busted OS X kqueue only accepts 1 kevent at a time for event in events: self._poller.control([event], 0) else: self._poller.control(events, 0)
def register(self, fd, flags): events = [] if flags & self.POLLIN: events.append(select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)) if flags & self.POLLOUT: events.append(select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD | select.KQ_EV_ENABLE)) self._kqueue.control(events, 0)
def test_kqueue(self): with self.socketpair() as (client, server): kq = emulation.select.green_kqueue() events = [ select.kevent(client.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD), select.kevent(client.fileno(), select.KQ_FILTER_WRITE, select.KQ_EV_ADD), select.kevent(server.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD), select.kevent(server.fileno(), select.KQ_FILTER_WRITE, select.KQ_EV_ADD)] if sys.platform == 'darwin': for event in events: # stupid busted OS X kqueue kq.control([event], 0) else: kq.control(events, 0) events = [(ke.ident, ke.filter) for ke in kq.control(None, 4, 0)] assert (client.fileno(), select.KQ_FILTER_WRITE) in events assert (client.fileno(), select.KQ_FILTER_READ) not in events assert (server.fileno(), select.KQ_FILTER_WRITE) in events assert (server.fileno(), select.KQ_FILTER_READ) not in events client.send("hello") events = [(ke.ident, ke.filter) for ke in kq.control(None, 4, 0)] assert (client.fileno(), select.KQ_FILTER_WRITE) in events assert (client.fileno(), select.KQ_FILTER_READ) not in events assert (server.fileno(), select.KQ_FILTER_WRITE) in events assert (server.fileno(), select.KQ_FILTER_READ) in events
def watch(self, fileobj, read=False, write=False): if not (read or write): raise ValueError('either read or write must be specified') if hasattr(fileobj, 'fileno'): fileno = fileobj.fileno() else: fileno = fileobj files_map = self._files_map try: del files_map[fileno] except KeyError: pass kevents = [] if read: kevents.append(select.kevent( fileno, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ONESHOT)) if write: kevents.append(select.kevent( fileno, select.KQ_FILTER_WRITE, select.KQ_EV_ADD | select.KQ_EV_ONESHOT)) files_map[fileno] = (fileobj, kevents)
def _modify_fd_events(self, fileno, events, events_to_clear, events_to_set): """The base class invoikes this method to notify the implementation to modify an already registered file descriptor. The request must be ignored if the poller is not activated. :param int fileno: The file descriptor :param int events: absolute events (READ, WRITE, ERROR) :param int events_to_clear: The events to clear (READ, WRITE, ERROR) :param int events_to_set: The events to set (READ, WRITE, ERROR) """ if self._kqueue is None: return kevents = list() if events_to_clear & READ: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) if events_to_set & READ: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if events_to_clear & WRITE: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) if events_to_set & WRITE: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) self._kqueue.control(kevents, 0)
def update_handler(self, fileno, events): """Set the events to the current events :param int fileno: The file descriptor :param int events: The event mask """ kevents = list() if not events & READ: if fileno in self._fd_events[READ]: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) else: if fileno not in self._fd_events[READ]: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if not events & WRITE: if fileno in self._fd_events[WRITE]: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) else: if fileno not in self._fd_events[WRITE]: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) for event in kevents: self._kqueue.control([event], 0) super(KQueuePoller, self).update_handler(fileno, events)
def run(self): try: while self.signal: events = self.kq.control(self.kevent, 5, None) for event in events: if event.ident == self._socket.fileno(): conn, addr = self._socket.accept() new_event = [ select.kevent(conn.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE) ] self.kq.control(new_event, 0, 0) self.connections[conn.fileno()] = conn else: conn = self.connections[event.ident] buf = conn.recv(1024) if not buf: conn.close() continue self.announce.uppercase(buf.decode("utf-8", "replace").strip()) finally: self.kq.control([select.kevent(self._socket.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)], 0, None) self.kq.close() self._socket.close()
def update_handler(self, fileno, events): """Set the events to the current events :param int fileno: The file descriptor :param int events: The event mask """ # No need to update if our events are the same if self.events == events: return kevents = list() if not events & READ: if self.events & READ: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) else: if not self.events & READ: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if not events & WRITE: if self.events & WRITE: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) else: if not self.events & WRITE: kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) for event in kevents: self._kqueue.control([event], 0) self.events = events
def loop_kqueue(timeout=0.0, map=None): if map is None: map = socket_map if timeout is not None: # timeout is in milliseconds timeout = int(timeout*1000) kq = select.kqueue() if map: evs = [] for fd, obj in map.items(): flags = select.KQ_EV_ADD | select.KQ_EV_CLEAR if obj.readable(): evs.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=flags)) if obj.writable(): evs.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=flags)) r_evs = kq.control(evs, 100, timeout) for ev in r_evs: obj = map.get(ev.ident) if obj is None: continue try: if ev.filter == select.KQ_FILTER_READ: obj.handle_read_event() if ev.filter == select.KQ_FILTER_WRITE: obj.handle_write_event() except socket.error, e: if e.args[0] not in (EBADF, ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED): obj.handle_error() else: obj.handle_close() except _reraised_exceptions: raise except:
def __watch(self): kq = select.kqueue() passwd_fd = os.open(self.passwd_filename, os.O_RDONLY) group_fd = os.open(self.group_filename, os.O_RDONLY) ev = [ select.kevent( passwd_fd, filter=select.KQ_FILTER_VNODE, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE, fflags=select.KQ_NOTE_WRITE | select.KQ_NOTE_EXTEND | select.KQ_NOTE_RENAME ), select.kevent( group_fd, filter=select.KQ_FILTER_VNODE, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE, fflags=select.KQ_NOTE_WRITE | select.KQ_NOTE_EXTEND | select.KQ_NOTE_RENAME ) ] kq.control(ev, 0) while True: event, = kq.control(None, 1) name = self.passwd_filename if event.ident == passwd_fd else self.group_filename logger.warning('{0} was modified, reloading'.format(name)) self.__load()
def unregister(self, fo): fd = None try: fd = int(fo) except: pass if fd is None: if hasattr(fo, 'fileno') and callable(fo.fileno): fd = fo.fileno() else: raise Error("File object '%s' is neither 'int' nor object with fileno() method" % (str(fo),)) if fd in self._fd_map: del self._fd_map[fd] if self._mode == PL_KQUEUE: # pragma: no cover ev = select.kevent(fo, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE) try: self._kq.control([ev], 0, 0) except: pass ev = select.kevent(fo, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE) try: self._kq.control([ev], 0, 0) except: pass elif self._mode == PL_POLL: return self._poll.unregister(fo) elif self._mode == PL_SELECT: self._rfos.discard(fo) self._wfos.discard(fo) self._xfos.discard(fo)
def update_handler(self, fileno, events): # No need to update if our events are the same if self.events == events: return # Keep a list of the events we want to pass into _kqueue.control kevents = list() # Build our list of kevents based upon if we have to add or remove # events and each event gets its own operation # We don't want READ if not events & READ: # We did have a read last time if self.events & READ: # Remove READ kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) # We do want READ else: # We did not have a read last time if not self.events & READ: # Add READ kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) # We don't want write events if not events & WRITE: # We had a write last time if self.events & WRITE: # Remove it kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) # We do want write events else: # We didn't have a WRITE last time if not self.events & WRITE: # Add write kevents.append(select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) # Send our event changes to kqueue control for event in kevents: self._kqueue.control([event], 0) # Carry the state we just sent self.events = events
def _control(self, fd, mode, flags): events = [] if mode & POLL_IN: events.append(select.kevent(fd, select.KQ_FILTER_READ, flags)) if mode & POLL_OUT: events.append(select.kevent(fd, select.KQ_FILTER_WRITE, flags)) for e in events: self._kqueue.control([e], 0)
def _control(self, fd, mode, flags): events = [] if mode & self.EV_IN: events.append(select.kevent(fd, select.KQ_FILTER_READ, flags)) if mode & self.EV_OUT: events.append(select.kevent(fd, select.KQ_FILTER_WRITE, flags)) for e in events: self._poller.control([e], 0)
def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) if events & EVENT_READ: kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_ADD) self._kqueue.control([kev], 0, 0) if events & EVENT_WRITE: kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD) self._kqueue.control([kev], 0, 0) return key
def _unregisterForEvents(self, fileno): readKE = select.kevent(ident = fileno, filter = select.KQ_FILTER_READ, flags = select.KQ_EV_DELETE) writeKE = select.kevent(ident = fileno, filter = select.KQ_FILTER_WRITE, flags = select.KQ_EV_DELETE) self.__controlKqueue(changeList = [readKE, writeKE]) self.__numFDs -= 1
def run(self): poller = kqueue() fds = {} events = [] while True: while not self.inputqueue.empty(): # loop through the queue and gather new pipes to add the # kernel queue buff, pipe, mode = self.inputqueue.get() if 'r' in mode: events.append(kevent(pipe, KQ_FILTER_READ, KQ_EV_ADD)) elif 'w' in mode: events.append(kevent(pipe, KQ_FILTER_WRITE, KQ_EV_ADD)) else: continue fds[pipe.fileno()] = (weakref.ref(buff), pipe) if len(events) == 0: events = None events = poller.control(events, 16, 0.1) for i in range(len(events)): # loop through response and handle events event = events.pop() buff, pipe = fds[event.ident] if buff() is None: # buffer object has closed out from underneath us # pipe will be automatically removed from kqueue pipe.close() del fds[event.ident] continue if (abs(event.filter) & abs(KQ_FILTER_READ)) and event.data: # new data has come in, push into the buffer buff().write(pipe.read(event.data)) if (abs(event.filter) & abs(KQ_FILTER_WRITE)) and event.data: # space is available to write data pipe.write(buff().read(\ min(buff()._nbytes, event.data, 2**16))) if abs(event.flags) & abs(KQ_EV_EOF): # pipe has been closed and all IO has been processed # pipe will be automatically removed from kqueue buff().close() pipe.close() del fds[event.ident] if len(fds) == 0: # no pipes referenced if self.idletime + 20 < time(): # idle timeout reached, terminate break sleep(0.1) else: self.idletime = time()
def _cleanup(self): self._kqueue.control([select.kevent(self._fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) self._kqueue.control([select.kevent(self._write_trigger, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) if self._write_in_last_poll: return [select.kevent(self._fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)]
def _control(self, fileno, events, flags): if events & Engine.WRITE: event = select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=flags) self._kqueue.control([event], 0) if events & Engine.READ: event = select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=flags) self._kqueue.control([event], 0)
def _control(self, fd, events, flags): kevents = [] if events & IOLoop.WRITE: kevents.append(select.kevent( fd, filter=select.KQ_FILTER_WRITE, flags=flags)) if events & IOLoop.READ or not kevents: kevents.append(select.kevent( fd, filter=select.KQ_FILTER_READ, flags=flags)) for kevent in kevents: self._kqueue.control([kevent], 0)
def __init__(self, fd, write_trigger): self._fd = fd self._write_trigger = write_trigger self._kqueue = select.kqueue() self._kqueue.control([select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_ADD)], 0) self._kqueue.control([select.kevent(write_trigger, select.KQ_FILTER_READ, select.KQ_EV_ADD)], 0) self._write_in_last_poll = False
def _control(self, fd, mode, flags): events = [] # Compare will use & if mode & POLL_IN: events.append(select.kevent(fd, select.KQ_FILTER_READ, flags)) if mode & POLL_OUT: events.append(select.kevent(fd, select.KQ_FILTER_WRITE, flags)) # Add it to kqueue for e in events: self._kqueue.control([e], 0)
def _changelist(self, write_wanted): if write_wanted and not self._write_in_last_poll: self._write_in_last_poll = True return [select.kevent(self._fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD)] elif self._write_in_last_poll and not write_wanted: self._write_in_last_poll = False return [select.kevent(self._fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)] return None
def register(self, fo, eventmask=POLLIN|POLLOUT): fd = None try: # This tests that the fd is an int type # In python2, this will also coerce a long # to an int. # fd = int(fo) except: pass if fd is None: if hasattr(fo, 'fileno') and callable(fo.fileno): fd = fo.fileno() else: raise Error("File object '%s' is neither 'int' nor object with fileno() method" % (str(fo),)) if not isinstance(fd, int): raise Error("File object '%s' fileno() method did not return an 'int'" % (str(fo),)) # Trigger an exception if the fd in not an open file. # os.fstat(fd) if not self._has_registered: if self._mode == PL_KQUEUE: # pragma: no cover self._kq = select.kqueue() elif self._mode == PL_POLL: self._poll = select.poll() elif self._mode == PL_SELECT: self._rfos = set() self._wfos = set() self._xfos = set() self._has_registered = True if self._mode == PL_KQUEUE: # pragma: no cover if eventmask & POLLPRI: raise Error("POLLPRI is not supported in %s mode", self.get_mode_name(self._mode)) self.unregister(fo) kl = [] if eventmask & POLLIN: kl.append(select.kevent(fo, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if eventmask & POLLOUT: kl.append(select.kevent(fo, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) self._fd_map[fd] = fo self._kq.control(kl, 0, 0) elif self._mode == PL_POLL: self._fd_map[fd] = fo return self._poll.register(fo, eventmask) elif self._mode == PL_SELECT: self.unregister(fo) self._fd_map[fd] = fo if eventmask & POLLIN: self._rfos.add(fo) if eventmask & POLLOUT: self._wfos.add(fo) if eventmask & POLLPRI: self._xfos.add(fo)
def unregister(self, fileobj): key = super().unregister(fileobj) if key.events & EVENT_READ: kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) self._kqueue.control([kev], 0, 0) if key.events & EVENT_WRITE: kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) self._kqueue.control([kev], 0, 0) return key
def _control(self, fd, events, flags): kevents = [] if events & IOLoop.WRITE: kevents.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=flags)) if events & IOLoop.READ or not kevents: # Always read when there is not a write kevents.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=flags)) # Even though control() takes a list, it seems to return EINVAL # on Mac OS X (10.6) when there is more than one event in the list. for kevent in kevents: self._kqueue.control([kevent], 0)
def __add_ev_read(self, fileno): """ Note:if the event exists,it will not do anything """ if fileno not in self.__rlist and self.__async_mode == "select": self.__rlist.append(fileno) if self.__async_mode == "epoll": if fileno not in self.__epoll_register_info: self.__epoll_register_info[fileno] = None eventmask = self.__epoll_register_info[fileno] event = select.EPOLLIN if eventmask == None: eventmask = event self.__epoll_object.register(fileno, eventmask) self.__epoll_register_info[fileno] = eventmask return is_register_read = (eventmask & select.EPOLLIN) == select.EPOLLIN if is_register_read == False: eventmask = event | eventmask self.__epoll_object.modify(fileno, eventmask) if self.__async_mode == "kqueue": filter_ = select.KQ_FILTER_READ flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE if fileno not in self.__kqueue_event_map: kevent = select.kevent(fileno, filter_, flags) kevent.udata = 0 else: kevent = self.__kqueue_event_map[fileno] read_exists = (kevent.udata & EV_TYPE_READ) == EV_TYPE_READ if read_exists == False: kevent.filter = filter_ kevent.udata = (kevent.udata | EV_TYPE_READ) kevent.flags = flags if fileno not in self.__kqueue_change_event_map: self.__kqueue_change_event_map[fileno] = [] self.__kqueue_change_event_map[fileno].append(kevent) '''''' return
def update_handler(self, fileno, events): """Set the events to the current events :param int fileno: The file descriptor :param int events: The event mask """ # No need to update if our events are the same if self.events == events: return kevents = list() if not events & READ: if self.events & READ: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) else: if not self.events & READ: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if not events & WRITE: if self.events & WRITE: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) else: if not self.events & WRITE: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) for event in kevents: self._kqueue.control([event], 0) self.events = events
def modify(self, disp): c = [] if disp.mask & self.IN: if not (disp.curmask & self.IN): c.append( select.kevent(disp.fd, select.KQ_FILTER_READ, select.KQ_EV_ADD)) elif disp.curmask & self.IN: c.append( select.kevent(disp.fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)) if disp.mask & self.OUT: if not (disp.curmask & self.OUT): c.append( select.kevent(disp.fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD)) elif disp.curmask & self.OUT: c.append( select.kevent(disp.fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)) if c: self.kqueue.control(c, 0) disp.curmask = disp.mask
def dropPid(self, pid): assert pid in self.pidmap try: event = select.kevent(ident=pid, filter=select.KQ_FILTER_PROC, flags=select.KQ_EV_DELETE, fflags=select.KQ_NOTE_EXIT) self.kq.control([event], 0) except: # We could have already pulled the process death out and it's sitting # in our poll list; kqueue has removed it. pass del self.pidmap[pid]
def modify(self, fd, read=True, write=True, error=True): """ Modify a file descriptor already registered in the kqueue to change the events being monitored. """ kevents = [] add_flags = select.KQ_EV_ADD if self._edge_triggered: add_flags = add_flags | select.KQ_EV_CLEAR if read and not fd in self._read_fds: kevents.append( select.kevent(fd, filter=select.KQ_FILTER_READ, flags=add_flags)) self._read_fds.add(fd) elif not read and fd in self._read_fds: kevents.append( select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) self._read_fds.discard(fd) if write and not fd in self._write_fds: kevents.append( select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=add_flags)) self._write_fds.add(fd) elif not write and fd in self._write_fds: kevents.append( select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) self._write_fds.discard(fd) if error: self._error_fds.add(fd) else: self._error_fds.discard(fd) for kevent in kevents: self._kqueue.control([kevent], 0)
def _control(self, fd, flag, flags): kevents = [] # 如果事件位掩码匹配可读 if flag & select.POLLIN: # select.kevent 方法的返回值是内核事件,也就是需要添加或删除的事件 # 把返回值添加到 kevents 列表,后面使用 kqueue 的 control 方法处理 # 该方法的参数:套接字的文件描述符、过滤常数、行为常数 # 过滤常数是负整数,添加可读事件监听使用 select.KQ_FILTER_READ # 其作用跟 poll.register 中的 select.POLLIN 是一样的 kevents.append(select.kevent( fd, filter = select.KQ_FILTER_READ, flags=flags)) # 如果事件位掩码匹配可写 if flag & select.POLLOUT: kevents.append(select.kevent( fd, filter = select.KQ_FILTER_WRITE, flags=flags)) for kevent in kevents: # control 方法处理 kevent 列表里的所有事件 # 第一个参数为内核事件的可迭代对象 # 第二个参数是最大事件数,必须是 0 或正整数 # 第二个参数如果为负会抛出异常,固定值 0 表示无限制 # 第三个参数 timeout 没有写 self._kqueue.control([kevent], 0)
async def _wait_common(self, fd, filter): if not isinstance(fd, int): fd = fd.fileno() flags = select.KQ_EV_ADD | select.KQ_EV_ONESHOT event = select.kevent(fd, filter, flags) self._kqueue.control([event], 0) def abort(_): event = select.kevent(fd, filter, select.KQ_EV_DELETE) self._kqueue.control([event], 0) return _core.Abort.SUCCEEDED await self.wait_kevent(fd, filter, abort)
def test_create_event(self): fd = sys.stderr.fileno() ev = select.kevent(fd) other = select.kevent(1000) self.assertEqual(ev.ident, fd) self.assertEqual(ev.filter, select.KQ_FILTER_READ) self.assertEqual(ev.flags, select.KQ_EV_ADD) self.assertEqual(ev.fflags, 0) self.assertEqual(ev.data, 0) self.assertEqual(ev.udata, 0) self.assertEqual(ev, ev) self.assertNotEqual(ev, other) self.assertEqual(cmp(ev, other), -1) self.assertTrue(ev < other) self.assertTrue(other >= ev) self.assertRaises(TypeError, cmp, ev, None) self.assertRaises(TypeError, cmp, ev, 1) self.assertRaises(TypeError, cmp, ev, "ev") ev = select.kevent(fd, select.KQ_FILTER_WRITE) self.assertEqual(ev.ident, fd) self.assertEqual(ev.filter, select.KQ_FILTER_WRITE) self.assertEqual(ev.flags, select.KQ_EV_ADD) self.assertEqual(ev.fflags, 0) self.assertEqual(ev.data, 0) self.assertEqual(ev.udata, 0) self.assertEqual(ev, ev) self.assertNotEqual(ev, other) ev = select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_ONESHOT) self.assertEqual(ev.ident, fd) self.assertEqual(ev.filter, select.KQ_FILTER_WRITE) self.assertEqual(ev.flags, select.KQ_EV_ONESHOT) self.assertEqual(ev.fflags, 0) self.assertEqual(ev.data, 0) self.assertEqual(ev.udata, 0) self.assertEqual(ev, ev) self.assertNotEqual(ev, other) ev = select.kevent(1, 2, 3, 4, 5, 6) self.assertEqual(ev.ident, 1) self.assertEqual(ev.filter, 2) self.assertEqual(ev.flags, 3) self.assertEqual(ev.fflags, 4) self.assertEqual(ev.data, 5) self.assertEqual(ev.udata, 6) self.assertEqual(ev, ev) self.assertNotEqual(ev, other) bignum = sys.maxsize * 2 + 1 ev = select.kevent(bignum, 1, 2, 3, sys.maxsize, bignum) self.assertEqual(ev.ident, bignum) self.assertEqual(ev.filter, 1) self.assertEqual(ev.flags, 2) self.assertEqual(ev.fflags, 3) self.assertEqual(ev.data, sys.maxsize) self.assertEqual(ev.udata, bignum) self.assertEqual(ev, ev) self.assertNotEqual(ev, other)
def del_channel(self, map=None): """Delete a channel""" # pylint: disable=redefined-builtin fd = self._fileno if map is None: map = self._map if fd in map: del map[fd] if self._fileno: try: kqueue_poller.pollster.control([ select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) ], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: kqueue_poller.pollster.control([ select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) ], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: epoll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no epoll used, or not registered pass try: poll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no poll used, or not registered pass self._fileno = None self.poller_flags = 0 self.poller_filter = 0 self.poller_registered = False
def handle_tcp(client, remote): """ :param client: :type client: socket.socket :param remote: :type remote: socket.socket :return: """ events = [ select.kevent(client.fileno(), select.KQ_FILTER_READ), select.kevent(remote.fileno(), select.KQ_FILTER_READ) ] try: while True: r_events = kq.control(events, 1) for r in r_events: if r.ident == client.fileno(): print("data from client") client_data = client.recv(1024 * 100) if len(client_data) > 0: print("client_data is {}".format(client_data)) remote.sendall(client_data) else: break elif r.ident == remote.fileno(): print("data from remote") remote_data = remote.recv(1024 * 100) if len(remote_data) > 0: print("remote_data is {}".format(remote_data)) client.sendall(remote_data) else: break except Exception as e: raise e finally: client.close() remote.close()
def _modify_fd_events(self, fileno, events, events_to_clear, events_to_set): """The base class invoikes this method to notify the implementation to modify an already registered file descriptor. The request must be ignored if the poller is not activated. :param int fileno: The file descriptor :param int events: absolute events (READ, WRITE, ERROR) :param int events_to_clear: The events to clear (READ, WRITE, ERROR) :param int events_to_set: The events to set (READ, WRITE, ERROR) """ if self._kqueue is None: return kevents = list() if events_to_clear & READ: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) if events_to_set & READ: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if events_to_clear & WRITE: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) if events_to_set & WRITE: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) self._kqueue.control(kevents, 0)
def run(self): if ':' in self.arg: path, lines = self.arg.rsplit(':', 1) lines = int(lines) else: path = self.arg lines = 3 if not os.path.exists(path): # FIXME: Error? return bufsize = 8192 fsize = os.stat(path).st_size if fsize < bufsize: bufsize = fsize i = 0 with open(path) as f: data = [] while True: i += 1 if bufsize * i > fsize: break f.seek(fsize - bufsize * i) data.extend(f.readlines()) if len(data) >= lines or f.tell() == 0: break self.send_event('ADDED', fields={'data': ''.join(data[-lines:])}) f.seek(fsize) kqueue = select.kqueue() ev = [ select.kevent( f.fileno(), filter=select.KQ_FILTER_VNODE, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | select.KQ_EV_CLEAR, fflags=select.KQ_NOTE_DELETE | select.KQ_NOTE_EXTEND | select.KQ_NOTE_WRITE | select.KQ_NOTE_ATTRIB, ) ] kqueue.control(ev, 0, 0) while not self._cancel.is_set(): events = kqueue.control([], 1, 1) if not events: continue # TODO: handle other file operations other than just extend/write self.send_event('ADDED', fields={'data': f.read()})
def serve_forever_bsd(self, max_events=1000): kqueue = select.kqueue() kevents = [select.kevent(self.socket.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)] index = 0 request_addr = dict() while True: events = kqueue.control(kevents, max_events) for event in events: # socket进来,将event加入监听 if event.ident == self.socket.fileno(): request, client_address = self.socket.accept() index += 1 request_addr[index] = (request, client_address) kevents.append(select.kevent(request.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD, udata=index)) elif event.filter == select.KQ_FILTER_READ and event.udata > 0 and event.flags == select.KQ_EV_ADD: try: kevents.remove( select.kevent(request_addr[event.udata][0].fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD, udata=event.udata)) except Exception as e: pass # t = Thread(target=self._handle_request_noblock_bsd, args=request_addr[event.udata]) self._handle_request_noblock_bsd(*request_addr[event.udata])
def modifyRegistrationForEvents(self, asyncSocket, readEvents, writeEvents): fileno = asyncSocket.fileno() if readEvents: readKE = select.kevent(ident=fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ENABLE) else: readKE = select.kevent(ident=fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DISABLE) if writeEvents: writeKE = select.kevent(ident=fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ENABLE) else: writeKE = select.kevent(ident=fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DISABLE) # Should be able to put readKE and writeKE in a list in # one call to kqueue.control, but this is broken due to Python issue 5910 self.__kqueue.control([readKE], 0, 0) self.__kqueue.control([writeKE], 0, 0)
def trigger(self, fileno): if fileno == -1: logger.error("tried to trigger a connection with filenumber == -1") return if self._connections[fileno].outbuffer: if hasattr(select, 'epoll'): self._epoll.modify(fileno, self._rw) elif hasattr(select, 'kqueue'): event = [ select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD | KQ_EV_ONESHOT) ] self._kqueue.control(event, 0, 0)
def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('0.0.0.0', 5555)) server_socket.listen(5) kq = select.kqueue() kq.control([ select.kevent(server_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD) ], 0, 0) connections = {} while True: events = kq.control([], 10000) for event in events: if server_socket.fileno() == event.ident: (client_socket, client_address) = server_socket.accept() print 'got connection from', client_address kq.control([ select.kevent(client_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD) ], 0, 0) connections[client_socket.fileno()] = client_socket elif event.filter == select.KQ_FILTER_READ: client_socket = connections[event.ident] data = client_socket.recv(4096) if data: client_socket.send(data) else: kq.control([ select.kevent(client_socket.fileno(), select.KQ_FILTER_READ, select.KQ_EV_DELETE) ], 0, 0) client_socket.close() connections.pop(event.ident)
def _trigger(self, fd, **params): """ We need events to fire on appearance because the code doesn't see the file until after it has been created. In WF_KQUEUE mode, this simulates triggering an event by firing a oneshot timer event to fire immediately (0 msecs). Because this uses the file descriptor as the timer identity and get() doesn't care what filter actually fired the event, the outside world sees this as a file change. In WF_INOTIFYX mode, this triggers an event by setting IN_OPEN on the inotify watch, opening the file in read-only mode, closing it, and removing the IN_OPEN setting. The file is not discovered unless it can be opened so this is reliable. In WF_POLLING mode, this resets our knowledge of the stat info, and then triggers file activity to wake up the caller. """ log = self._getparam('log', self._discard, **params) if self._mode == WF_KQUEUE: try: ev = select.kevent(fd, filter=select.KQ_FILTER_TIMER, flags=select.KQ_EV_ADD | select.KQ_EV_CLEAR | select.KQ_EV_ONESHOT, data=0) self._kq.control([ev], 0, 0) log.debug("Added timer event following pending file promotion") except Exception as e: log.error("Failed to add timer event following pending file promotion -- %s", str(e)) elif self._mode == WF_INOTIFYX: if fd in self.fds_open: try: path = self.fds_open[fd] nfd = inotifyx.add_watch(self._inx_fd, path, self._inx_mask|inotifyx.IN_OPEN) if nfd != fd: raise Exception("Assertion failed: IN_OPEN add_watch() set gave new wd") tfd = os.open(path, os.O_RDONLY) try: os.close(tfd) except: pass nfd = inotifyx.add_watch(self._inx_fd, path, self._inx_mask) if nfd != fd: raise Exception("Assertion failed: IN_OPEN add_watch() clear gave new wd") except Exception as e: log.error("Failed to trigger event via os.open() following pending file promotion -- %s", str(e)) else: log.error("Pending file promotion of unknown wd %d failed", fd) elif self._mode == WF_POLLING: self._poll_stat[fd] = () self._poll_trigger()
def __add_ev_write(self, fileno): if fileno not in self.__wlist and self.__async_mode == "select": self.__wlist.append(fileno) if self.__async_mode == "epoll": if fileno not in self.__epoll_register_info: self.__epoll_register_info[fileno] = None eventmask = self.__epoll_register_info[fileno] event = select.EPOLLOUT if eventmask == None: eventmask = event self.__epoll_object.register(fileno, eventmask) self.__epoll_register_info[fileno] = eventmask return is_register_write = (eventmask & select.EPOLLOUT) == select.EPOLLOUT if is_register_write == False: eventmask = event | eventmask self.__epoll_object.modify(fileno, eventmask) if self.__async_mode == "kqueue": filter_ = select.KQ_FILTER_WRITE flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE if fileno not in self.__kqueue_event_map: kevent = select.kevent(fileno, filter_, flags) kevent.udata = 0 else: kevent = self.__kqueue_event_map[fileno] write_exists = (kevent.udata & EV_TYPE_WRITE) == EV_TYPE_WRITE if write_exists == False: kevent.filter = filter_ kevent.flags = flags kevent.udata = (kevent.udata | EV_TYPE_WRITE) if fileno not in self.__kqueue_change_event_map: self.__kqueue_change_event_map[fileno] = [] self.__kqueue_change_event_map[fileno].append(kevent) '''''' return
def del_channel(self, map=None): fd = self._fileno if map is None: map = self._map if fd in map: #self.log_info('closing channel %d:%s' % (fd, self)) del map[fd] if self._fileno: try: kqueue_poller.pollster.control([ select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) ], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: kqueue_poller.pollster.control([ select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) ], 0) except (AttributeError, KeyError, TypeError, IOError, OSError): pass try: epoll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no epoll used, or not registered pass try: poll_poller.pollster.unregister(fd) except (AttributeError, KeyError, TypeError, IOError): # no poll used, or not registered pass self._fileno = None self.poller_flags = 0 self.poller_filter = 0 self.poller_registered = False
def update_handler(self, fileno, events): """Set the events to the current events :param int fileno: The file descriptor :param int events: The event mask """ kevents = list() if not events & READ: if fileno in self._fd_events[READ]: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)) else: if fileno not in self._fd_events[READ]: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)) if not events & WRITE: if fileno in self._fd_events[WRITE]: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)) else: if fileno not in self._fd_events[WRITE]: kevents.append( select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)) for event in kevents: self._kqueue.control([event], 0) super(KQueuePoller, self).update_handler(fileno, events)
def run(self): self.msg("Entering mainloop") try: os = uname()[0] if os in ["FreeBSD", "OpenBSD"]: kqueue = select.kqueue.fromfd(self.sock.fileno()) elif os in ["Linux"]: epoll = select.epoll.fromfd(self.sock.fileno()) while not self.stop: if os in ["FreeBSD", "OpenBSD"]: select.kevent(kqueue) elif os in ["Linux"]: epoll.poll() else: select(self.sock, [], []) try: data = self.sock.recv(self.buffer_size) msg = parse_message(data, self.year) self.queue.put(msg) except: pass except KeyboardInterrupt: self.stop = True self.msg("Exiting")
def test_kqueue(self): with self.socketpair() as (client, server): kq = emulation.select.green_kqueue() events = [ select.kevent(client.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD), select.kevent(client.fileno(), select.KQ_FILTER_WRITE, select.KQ_EV_ADD), select.kevent(server.fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD), select.kevent(server.fileno(), select.KQ_FILTER_WRITE, select.KQ_EV_ADD) ] if sys.platform == 'darwin': for event in events: # stupid busted OS X kqueue kq.control([event], 0) else: kq.control(events, 0) events = [(ke.ident, ke.filter) for ke in kq.control(None, 4, 0)] assert (client.fileno(), select.KQ_FILTER_WRITE) in events assert (client.fileno(), select.KQ_FILTER_READ) not in events assert (server.fileno(), select.KQ_FILTER_WRITE) in events assert (server.fileno(), select.KQ_FILTER_READ) not in events client.send("hello") events = [(ke.ident, ke.filter) for ke in kq.control(None, 4, 0)] assert (client.fileno(), select.KQ_FILTER_WRITE) in events assert (client.fileno(), select.KQ_FILTER_READ) not in events assert (server.fileno(), select.KQ_FILTER_WRITE) in events assert (server.fileno(), select.KQ_FILTER_READ) in events
def start(self): while True: eventlist = self.kq.control(None, 100, 1) for event in eventlist: send = True if event.flags & select.KQ_EV_ERROR: send = self.onSocketEvent(event.ident, sockConnect.socketEventExcept) elif event.filter == select.KQ_FILTER_READ: send = self.onSocketEvent(event.ident, sockConnect.socketEventCanRecv) elif event.filter == select.KQ_FILTER_WRITE: if event.flags & select.KQ_EV_EOF: send = self.onSocketEvent( event.ident, sockConnect.socketEventExcept) else: send = self.onSocketEvent( event.ident, sockConnect.socketEventCanSend) if not send: try: self.kq.control([ select.kevent(event.ident, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE) ], 0) except: pass try: self.kq.control([ select.kevent(event.ident, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE) ], 0) except: pass self._handlerCallback()
def onIOEventFlagsChanged(self, connect): fileno = connect._sock.fileno() changed = connect._ioEventFlags_keventSet ^ connect._ioEventFlags if changed & sockConnect.socketIOEventFlagsRead: flags = select.KQ_EV_ADD if ( connect._ioEventFlags & sockConnect.socketIOEventFlagsRead) else select.KQ_EV_DELETE self.kq.control([ select.kevent( fileno, filter=select.KQ_FILTER_READ, flags=flags) ], 0) # print connect,"KQ_FILTER_READ",flags if changed & sockConnect.socketIOEventFlagsWrite: flags = select.KQ_EV_ADD if ( connect._ioEventFlags & sockConnect.socketIOEventFlagsWrite) else select.KQ_EV_DELETE self.kq.control([ select.kevent( fileno, filter=select.KQ_FILTER_WRITE, flags=flags) ], 0) # print connect,"KQ_FILTER_WRITE",flags connect._ioEventFlags_keventSet = connect._ioEventFlags
def unregister(self, fo): fd = None try: fd = int(fo) except: pass if fd is None: if hasattr(fo, 'fileno') and callable(fo.fileno): fd = fo.fileno() else: raise Error( "File object '%s' is neither 'int' nor object with fileno() method" % (str(fo), )) if fd in self._fd_map: del self._fd_map[fd] if self._mode == PL_KQUEUE: # pragma: no cover ev = select.kevent(fo, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE) try: self._kq.control([ev], 0, 0) except: pass ev = select.kevent(fo, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE) try: self._kq.control([ev], 0, 0) except: pass elif self._mode == PL_POLL: return self._poll.unregister(fo) elif self._mode == PL_SELECT: self._rfos.discard(fo) self._wfos.discard(fo) self._xfos.discard(fo)
def worker(self): self.logger.debug('Opened tail stream on file {0} ({1} lines)'.format( self.path, self.backlog)) with io.open(self.fd, 'wb') as fd: with open(self.path, 'rb') as f: kq = select.kqueue() try: ev = [ select.kevent(fd.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE), select.kevent(f.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE) ] fd.write(self.tail(f, self.backlog)) fd.flush() kq.control(ev, 0) f.seek(0, os.SEEK_END) while True: event, = kq.control(None, 1) self.logger.debug('kqueue event {0}'.format(event)) if event.ident == fd.fileno(): if event.flags & select.KQ_EV_EOF or event.flags & select.KQ_EV_ERROR: break if event.ident == f.fileno(): fd.write(f.read()) fd.flush() finally: kq.close()
def add_watch(self, path): fd = os.open(path, O_EVTONLY) event = select.kevent( fd, filter=select.KQ_FILTER_VNODE, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | select.KQ_EV_CLEAR, fflags=select.KQ_NOTE_DELETE | select.KQ_NOTE_WRITE | select.KQ_NOTE_EXTEND | select.KQ_NOTE_ATTRIB | select.KQ_NOTE_LINK | select.KQ_NOTE_RENAME | select.KQ_NOTE_REVOKE, ) self._watch_list[event.ident] = (path, event, fd)
def register_connection(self, fileno, obj): if fileno == -1: logger.error( "tried to register a connection with filenumber == -1") return self._connections[fileno] = obj if hasattr(select, 'epoll'): self._epoll.register(fileno, self._ro) elif hasattr(select, 'kqueue'): event = [ select.kevent(fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD) ] self._kqueue.control(event, 0, 0)
def join_all(self, timeout=None, callback=None): with self._lock: not_done = self._members.copy() started = time() while timeout is None or not float_info.epsilon > timeout: if OS_MAC: if timeout == None: timeout = -1.0 ready = self._poller.control(None, 1, timeout) if OS_LIN: ready = self._poller.poll( timeout=-1.0 if timeout is None else timeout) if not timeout is None: timeout -= (time() - started) if OS_MAC: for fd in ready: fd = fd.ident self._poller.control( [kevent(fd, KQ_FILTER_READ, KQ_EV_DELETE)], 0) not_done.pop(fd) if callable(callback): callback(fd, self._members[fd]) if OS_LIN: for fd, flags in ready: self._poller.unregister(fd) not_done.pop(fd) if callable(callback): callback(fd, self._members[fd]) if 0 == len(not_done): return # some of the jobs are not done, we'll have to forcefully stop them for fd in not_done: if self._members[fd].terminate(): self._members[fd]._timed_out = True if callable(callback): callback(fd, self._members[fd])
def trigger(self, fileno): if fileno == -1: logger.error("tried to trigger a connection with filenumber == -1") return if self._connections[fileno].outbuffer: if hasattr(select, 'epoll'): self._epoll.modify(fileno, self._rw) elif hasattr(select, 'kqueue'): event = [ select.kevent(fileno, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD | KQ_EV_ONESHOT) ] self._kqueue.control(event, 0, 0) else: logger.error("trigger: Operating System without epoll or kqueue is currently not supported, please report this error")