2017-10-18 254 views
1

我想程序从龙卷风转换为ASYNCIO的第一步是使用实际ASYNCIO事件循环作为described here使用Python ASYNCIO等待GPIO中断

此应用程序在嵌入式Linux机器上运行,我使用通过sysfs/gpio subsystem的GPIO以及我正在等待中断的某些GPIO。我能直接在此整合到龙卷风IOLoop做:

# Register with the queue 
self.io_loop.add_handler(
    self.gpio._value_file, self._handle_interrupt, self.io_loop._EPOLLPRI | self.io_loop.ERROR 
) 

在代码块,_value_file是文件句柄的GPIO可以读取该文件。只要该GPIO上的中断可用,事件EPOLLPRI就会被触发。在龙卷风,这工作得很好。它会在中断到来后立即调用_handle_interrupt函数。

我的问题是,我一直没能到这个转换为本地ASYNCIO事件循环。在the documentation for watching file descriptors我只找到函数来添加读者和作家,但没有什么可以观察文件描述符上的通用事件掩码。我不能深入到代码自从进入。然而,看着龙卷风层从龙卷风IOLoop调用翻译成ASYNCIO IOLoop好像是这样的话:

def add_handler(self, fd, handler, events): 
    fd, fileobj = self.split_fd(fd) 
    if fd in self.handlers: 
     raise ValueError("fd %s added twice" % fd) 
    self.handlers[fd] = (fileobj, stack_context.wrap(handler)) 
    if events & IOLoop.READ: 
     self.asyncio_loop.add_reader(
      fd, self._handle_events, fd, IOLoop.READ) 
     self.readers.add(fd) 
    if events & IOLoop.WRITE: 
     self.asyncio_loop.add_writer(
      fd, self._handle_events, fd, IOLoop.WRITE) 
     self.writers.add(fd) 

只读和WRITE标志被翻译,所有其他标志被忽略。

有人能证实它是目前无法使用ASYNCIO来监视除了READ文件描述符的任何事件和写入事件?或者我做错了事,实际上有办法吗?

回答

2

我现在已经为自己找到了解决方案。我的主要信息来源是this thread in the Python-tulip groupthis piece of code,我不得不稍微采用。

主要观点是可以用来监视POLLPRI事件的epoll的本身就是一个文件描述符。每当epoll观看的FD上发生事件时,epoll文件描述符将生成一个POLLIN事件,该事件可以使用asyncio与add_reader进行观看。因此,而不是直接注册,我们手动创建一个epoll的结构,并与ioloop注册它,像这样:

self.epoll = select.epoll() 
self.io_loop.add_reader(self.epoll.fileno(), self._handle_interrupt) 

实际中断事件,然后注册到epoll的结构

self.epoll.register(self.gpio._value_file, select.POLLPRI) 

在这一点上,中断事件将在_handle_interrupt函数中收到。确保实际轮询epoll的结构在事件处理程序,否则会产生连续的读取事件

def _handle_interrupt(self): 
    self.epoll.poll(0) 
    ... 

,因为他们做了类似改用高层次selectors的低级别select功能是非常重要的事件标志过滤,如asyncio。剪断下面的代码是从selectors.EpollSelector

def register(self, fileobj, events, data=None): 
    key = super().register(fileobj, events, data) 
    epoll_events = 0 
    if events & EVENT_READ: 
     epoll_events |= select.EPOLLIN 
    if events & EVENT_WRITE: 
     epoll_events |= select.EPOLLOUT 
    try: 
     self._epoll.register(key.fd, epoll_events) 
    except BaseException: 
     super().unregister(fileobj) 
     raise 
    return key 

可以看出,除了那读写所有的事件进行过滤。因此,您不能使用高级界面来观察POLLPRI事件。因此,请使用低级别界面。

我希望这可以帮助人们解决这个问题。