Nir Soffer has uploaded a new change for review.

Change subject: vdsm: add eventfd and EventFile synchronization
......................................................................

vdsm: add eventfd and EventFile synchronization

Change-Id: I0d237f13c42b1f4505c90d30c6d3c3ecbd1e9fa7
Signed-off-by: Federico Simoncelli <fsimo...@redhat.com>
---
M lib/vdsm/Makefile.am
A lib/vdsm/eventfd.py
M tests/Makefile.am
A tests/eventfdTests.py
4 files changed, 251 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/87/33687/1

diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index 4bebf28..e712cad 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -25,6 +25,7 @@
        __init__.py \
        compat.py \
        define.py \
+       eventfd.py \
        exception.py \
        ipwrapper.py \
        libvirtconnection.py \
diff --git a/lib/vdsm/eventfd.py b/lib/vdsm/eventfd.py
new file mode 100644
index 0000000..b2a7084
--- /dev/null
+++ b/lib/vdsm/eventfd.py
@@ -0,0 +1,140 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+"""\
+This module provides the support for eventfd(2).
+
+More information about eventfd and usage examples can be found in the
+eventfd(2) man page.
+
+The EventFile class provides a single synchronization object exposing
+the python Event interface and associated eventfds.
+
+The eventfd() context manager returns a file descriptor that can be
+used to provide the event notice to select, poll and epoll, e.g.
+
+    import os
+    import sys
+    import select
+    import threading
+    import time
+    from vdsm.eventfd import EventFile, DATASIZE
+
+    e = EventFile()
+    p = select.epoll()
+
+    threading.Timer(5, e.set).start()
+
+    with e.eventfd() as efd:
+        p.register(efd, select.EPOLLIN)
+        p.register(sys.stdin.fileno(), select.EPOLLIN)
+
+        print "Echoing lines until event is received"
+        event_received = False
+
+        while not event_received:
+            for fileno, event in p.poll():
+                if not event & select.EPOLLIN:
+                    continue
+
+                if fileno == efd:
+                    os.read(efd, DATASIZE)
+                    event_received = True
+                elif fileno == sys.stdin.fileno():
+                    print os.read(sys.stdin.fileno(), 1024),
+
+        print "Event received!"
+
+
+The Event set() semantic is preserved in the eventfd context manager:
+if the event is set then the eventfd already contains the notification.
+This is both to maintain the semantic and to avoid possible races as:
+
+    if not e.is_set():
+        with e.eventfd() as efd:
+            ...
+"""
+
+import os
+import ctypes
+import threading
+
+from contextlib import contextmanager
+
+_libc = ctypes.CDLL('libc.so.6', use_errno=True)
+
+EFD_NONBLOCK = os.O_NONBLOCK
+EFD_CLOEXEC = 02000000  # os.O_CLOEXEC in python 3.3
+EFD_SEMAPHORE = 00000001
+
+DATASIZE = ctypes.sizeof(ctypes.c_ulonglong)
+
+
+def eventfd(initval, flags):
+    return _libc.eventfd(initval, flags)
+
+
+class EventFile(object):
+    def __init__(self, event=None):
+        self.__lock = threading.Lock()
+        self.__fds = set()
+        self.__event = event or threading.Event()
+
+    @staticmethod
+    def __fire_event(fd):
+        os.write(fd, ctypes.c_ulonglong(1))
+
+    def open_eventfd(self):
+        with self.__lock:
+            fd = eventfd(0, 0)
+
+            self.__fds.add(fd)
+
+            if self.__event.is_set():
+                self.__fire_event(fd)
+
+        return fd
+
+    @contextmanager
+    def eventfd(self):
+        fd = self.open_eventfd()
+
+        yield fd
+
+        with self.__lock:
+            self.__fds.remove(fd)
+            os.close(fd)
+
+    def isSet(self):
+        return self.__event.isSet()
+
+    is_set = isSet
+
+    def set(self):
+        with self.__lock:
+            self.__event.set()
+            for fd in self.__fds:
+                self.__fire_event(fd)
+
+    def clear(self):
+        self.__event.clear()
+
+    def wait(self, timeout=None, balancing=True):
+        self.__event.wait(timeout)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 449d7b1..120712e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -31,6 +31,7 @@
        clientifTests.py \
        configNetworkTests.py \
        domainMonitorTests.py \
+       eventfdTests.py \
        fileVolumeTests.py \
        fileUtilTests.py \
        fuserTests.py \
diff --git a/tests/eventfdTests.py b/tests/eventfdTests.py
new file mode 100644
index 0000000..be15248
--- /dev/null
+++ b/tests/eventfdTests.py
@@ -0,0 +1,109 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import os
+import select
+from vdsm.eventfd import EventFile, DATASIZE
+from nose.tools import timed, raises, TimeExpired
+
+TEST_TIMEOUT = 1
+WAIT_TIMEOUT = 2
+
+
+def test_set():
+    e = EventFile()
+    e.set()
+    assert e.is_set()
+    assert e.isSet()
+
+
+def text_clear():
+    e = EventFile()
+    e.set()
+    assert e.is_set()
+    e.clear()
+    assert not e.is_set()
+
+
+@timed(TEST_TIMEOUT)
+def test_wait_set():
+    e = EventFile()
+    e.set()
+    e.wait(WAIT_TIMEOUT)
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_wait_noset():
+    e = EventFile()
+    e.wait(WAIT_TIMEOUT)
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_earlyset():
+    e = EventFile()
+    e.set()
+    with e.eventfd() as fd:
+        assert len(__select_and_read(fd)) == DATASIZE
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_lateset():
+    e = EventFile()
+    with e.eventfd() as fd:
+        e.set()
+        assert len(__select_and_read(fd)) == DATASIZE
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_eventfd_noset():
+    e = EventFile()
+    with e.eventfd() as fd:
+        assert len(__select_and_read(fd)) != DATASIZE
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_multiple():
+    e = EventFile()
+    e.set()
+    with e.eventfd() as fd1:
+        assert len(__select_and_read(fd1)) == DATASIZE
+        with e.eventfd() as fd2:
+            assert len(__select_and_read(fd2)) == DATASIZE
+    with e.eventfd() as fd3:
+        assert len(__select_and_read(fd3)) == DATASIZE
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_eventfd_clear():
+    e = EventFile()
+    e.set()
+    e.clear()
+    with e.eventfd() as fd:
+        assert len(__select_and_read(fd)) != DATASIZE
+
+
+def __select_and_read(fd):
+    rd, wr, ex = select.select((fd,), (), (), WAIT_TIMEOUT)
+    if fd in rd:
+        return os.read(fd, DATASIZE)
+    return ''


-- 
To view, visit https://gerrit.ovirt.org/33687
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0d237f13c42b1f4505c90d30c6d3c3ecbd1e9fa7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimo...@redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <dan...@redhat.com>
Gerrit-Reviewer: Federico Simoncelli <fsimo...@redhat.com>
Gerrit-Reviewer: Francesco Romani <from...@redhat.com>
Gerrit-Reviewer: Jenkins CI
Gerrit-Reviewer: Jenkins CI RO
Gerrit-Reviewer: Nir Soffer <nsof...@redhat.com>
Gerrit-Reviewer: Saggi Mizrahi <smizr...@redhat.com>
Gerrit-Reviewer: gerrit-hooks <automat...@ovirt.org>
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/vdsm-patches@lists.fedorahosted.org

Reply via email to