EventFD

Module author: Aviv Palivoda <palaviv@gmail.com>

The python standard library threading.Event class provides a simple mechanisms for communication between threads: one thread signals an event and other threads wait for it. In many cases you would like to signal a thread that is currently waiting on a other events to happen using select/poll. The EventFD class provides a extension to the threading.Event class and can be used to stop the select/poll when signaled.

Note

EventFD support the windows operating system but it is not tested in the CI.

Note

EventFD use the linux eventfd but is not a python binding for eventfd. You might want to try:

Event Objects

The EventFD class is currently implemented with linux eventfd or os.pipe(). the EventFD class inherits from the eventfd._eventfd.BaseEventFD class.

class eventfd._eventfd.BaseEventFD

Class implementing event objects that has a fd that can be selected.

This EventFD class implements the same functions as a regular Event but it has a file descriptor. The file descriptor can be accessed using the fileno function. This event can be passed to select, poll and it will block until the event will be set.

clear()

Reset the internal flag to false.

Subsequently, threads calling wait() will block until set() is called to set the internal flag to true again.

fileno()

Return a file descriptor that can be selected.

You should not use this directly pass the EventFD object instead.

is_set()

Return true if and only if the internal flag is true.

set()

Set the internal flag to true.

All threads waiting for it to become true are awakened. Threads that call wait() once the flag is true will not block at all.

wait(timeout=None)

Block until the internal flag is true.

If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs.

When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).

This method returns the internal flag on exit, so it will always return True except if a timeout is given and the operation times out.

EXAMPLES

We will implement socketserver.TCPServer without polling using EventFD:

"""This is an example of python HTTP server without polling using the EventFD to shutdown the server"""

import threading
import select
from socketserver import TCPServer, BaseRequestHandler
import socket
import time

from eventfd import EventFD


class NonPollingHTTPServer(TCPServer):

    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        # using an EventFD to signal the server_forever to stop
        self.__shutdown_event = EventFD()
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        if bind_and_activate:
            try:
                self.server_bind()
                self.server_activate()
            except:
                self.server_close()
                raise

    # overriding the server_forever class to not poll.
    def serve_forever(self):
        self.__is_shut_down.clear()
        self.__shutdown_event.clear()
        try:
            while True:
                r, w, e = select.select([self.__shutdown_event, self], [], [])

                if self.__shutdown_event in r:
                    break

                if self in r:
                    self._handle_request_noblock()

                self.service_actions()
        finally:
            self.__is_shut_down.set()

    def shutdown(self):
        self.__shutdown_event.set()
        self.__is_shut_down.wait()


###############################################
# MyTCPHandler class and client function are
# from the python socketserver documentation.
###############################################

class MyTCPHandler(BaseRequestHandler):

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())


def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print("Received: {}".format(response))
    finally:
        sock.close()


def test():
    server = NonPollingHTTPServer(("localhost", 0), MyTCPHandler)
    ip, port = server.server_address

    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.daemon = True
    server_thread.start()

    client(ip, port, b"Hello World 1")
    client(ip, port, b"Hello World 2")
    client(ip, port, b"Hello World 3")

    print("requesting server shutdown at {}".format(time.time()))
    server.shutdown()
    print("server was shutdown at {}".format(time.time()))
    server.server_close()


if __name__ == "__main__":
    test()



Obtaining the Module

This module can be installed directly from the Python Package Index with pip:

pip install eventfd

Alternatively, you can download and unpack it manually from the eventfd PyPI page.

Development and Support

eventfd is developed and maintained on Github.

Problems and suggested improvements can be posted to the issue tracker.

Release History

0.2 (01-03-2016)

  • Using linux eventfd where eventfd is avaiable.
  • Travis CI using tox.
  • Support for windows using socket (only sockets can be selected in windows).

0.1 (27-02-2016)

  • EventFD using pipe.

Indices and tables