From 3457e9efa94be8eaa03d1a436ca7e189412c7b07 Mon Sep 17 00:00:00 2001 From: David Shea Date: Fri, 12 Jun 2015 09:31:08 -0400 Subject: [PATCH] - Retry interrupted system calls (#1230773) - Rearrange the build process to match current packaging recommendations --- python-pyudev.spec | 44 +++++++++++++---- pyudev-eintr-retry.patch | 102 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 pyudev-eintr-retry.patch diff --git a/python-pyudev.spec b/python-pyudev.spec index 5ce2a9c..6887611 100644 --- a/python-pyudev.spec +++ b/python-pyudev.spec @@ -1,13 +1,18 @@ Name: python-pyudev Version: 0.16.1 -Release: 2%{?dist} +Release: 3%{?dist} Summary: A libudev binding License: LGPLv2+ URL: http://pypi.python.org/pypi/pyudev Source0: http://pypi.python.org/packages/source/p/pyudev/pyudev-%{version}.tar.gz + +# Based on 0113ccdbba1aef69f3f890fd72622f24d79d907a in github.com/lunaryorn/pyudev.git Patch0: pyudev-0.16.1-global-libudev.patch +# Based on af9ba7b27478274a2f5f9676de662b079a3a8c22 in github.com/dashea/pyudev.git +Patch1: pyudev-eintr-retry.patch + BuildArch: noarch BuildRequires: python2-devel @@ -43,23 +48,38 @@ versions of udev as found on dated Linux systems may work, but are not officially supported. %prep -%setup -q -n pyudev-%{version} -%patch0 -p1 -b .global-libudev +%setup -qc +mv pyudev-%{version} python2 +pushd python2 rm -rf pyudev.egg-info -rm -rf %{py3dir} -cp -a . %{py3dir} +%patch0 -p1 -b .global-libudev +%patch1 -p1 -b .eintr-retry + +# Copy common doc files to the top directory +cp -pr COPYING README.rst CHANGES.rst ../ +popd + +cp -a python2 python3 %build +pushd python2 %{__python2} setup.py build +popd -( cd %{py3dir} && %{__python3} setup.py build ) +pushd python3 +%{__python3} setup.py build +popd %install -%{__python} setup.py install --skip-build --root $RPM_BUILD_ROOT +pushd python2 +%{__python2} setup.py install --skip-build --root $RPM_BUILD_ROOT +popd -( cd %{py3dir} && %{__python3} setup.py install --skip-build --root $RPM_BUILD_ROOT ) +pushd python3 +%{__python3} setup.py install --skip-build --root $RPM_BUILD_ROOT +popd %files %license COPYING @@ -74,10 +94,14 @@ cp -a . %{py3dir} %{python3_sitelib}/pyudev-%{version}-*.egg-info %changelog -* Wed Jan 28 2015 David Shea - 0.16-2 +* Fri Jun 12 2015 David Shea - 0.16.1-3 +- Retry interrupted system calls (#1230773) +- Rearrange the build process to match current packaging recommendations + +* Wed Jan 28 2015 David Shea - 0.16.1-2 - Use %%license for the license file -* Wed Dec 10 2014 David Shea - 0.16-1 +* Wed Dec 10 2014 David Shea - 0.16.1-1 - Update to pyudev-0.16.1 (#880644) - Apply a patch from upstream to remove a global reference to libudev (#1170337) diff --git a/pyudev-eintr-retry.patch b/pyudev-eintr-retry.patch new file mode 100644 index 0000000..7f61679 --- /dev/null +++ b/pyudev-eintr-retry.patch @@ -0,0 +1,102 @@ +diff -purN pyudev-0.16.1.orig/pyudev/monitor.py pyudev-0.16.1/pyudev/monitor.py +--- pyudev-0.16.1.orig/pyudev/monitor.py 2015-06-12 09:36:21.427469657 -0400 ++++ pyudev-0.16.1/pyudev/monitor.py 2015-06-12 09:37:05.483447685 -0400 +@@ -34,7 +34,7 @@ import select + from threading import Thread + from contextlib import closing + +-from pyudev._util import ensure_byte_string ++from pyudev._util import ensure_byte_string, eintr_retry_call + + from pyudev.core import Device + +@@ -337,7 +337,7 @@ class Monitor(object): + + .. versionadded:: 0.16 + """ +- rlist, _, _ = select.select([self], [], [], timeout) ++ rlist, _, _ = eintr_retry_call(select.select, [self], [], [], timeout) + if self in rlist: + return self._receive_device() + else: +@@ -407,7 +407,7 @@ class Monitor(object): + with closing(select.epoll()) as notifier: + notifier.register(self, select.EPOLLIN) + while True: +- events = notifier.poll() ++ events = eintr_retry_call(notifier.poll) + for event in events: + device = self._receive_device() + yield device.action, device +@@ -503,14 +503,14 @@ class MonitorObserver(Thread): + # and on the monitor + notifier.register(self.monitor, select.EPOLLIN) + while True: +- for fd, _ in notifier.poll(): ++ for fd, _ in eintr_retry_call(notifier.poll): + if fd == self._stop_event_source: + # in case of a stop event, close our pipe side, and + # return from the thread + os.close(self._stop_event_source) + return + else: +- device = self.monitor.poll(timeout=0) ++ device = eintr_retry_call(self.monitor.poll, timeout=0) + if device: + self._callback(device) + +@@ -530,7 +530,7 @@ class MonitorObserver(Thread): + return + try: + # emit a stop event to the thread +- os.write(self._stop_event_sink, b'\x01') ++ eintr_retry_call(os.write, self._stop_event_sink, b'\x01') + finally: + # close the out-of-thread side of the pipe + os.close(self._stop_event_sink) +diff -purN pyudev-0.16.1.orig/pyudev/_util.py pyudev-0.16.1/pyudev/_util.py +--- pyudev-0.16.1.orig/pyudev/_util.py 2015-06-12 09:36:21.428469657 -0400 ++++ pyudev-0.16.1/pyudev/_util.py 2015-06-12 09:36:45.923457440 -0400 +@@ -32,6 +32,7 @@ from __future__ import (print_function, + import os + import sys + import stat ++import errno + + + if sys.version_info[0] == 2: +@@ -141,3 +142,34 @@ def get_device_type(filename): + return 'block' + else: + raise ValueError('not a device file: {0!r}'.format(filename)) ++ ++ ++def eintr_retry_call(func, *args, **kwargs): ++ """ ++ Handle interruptions to an interruptible system call. ++ ++ Run an interruptible system call in a loop and retry if it raises EINTR. ++ The signal calls that my raise EINTR prior to Python 3.5 are listed in ++ PEP 0475. Any calls to these functions must be wrapped in eintr_retry_call ++ in order to handle EINTR returns in older versions of Python. ++ ++ This function is based on _eintr_retry_call in python's subprocess.py. ++ """ ++ ++ # select.error inherits from Exception instead of OSError in Python 2 ++ import select ++ ++ while True: ++ try: ++ return func(*args, **kwargs) ++ except (OSError, IOError, select.error) as e: ++ # If this is not an IOError or OSError, it's the old select.error ++ # type, which means that the errno is only accessible via subscript ++ if isinstance(e, (OSError, IOError)): ++ error_code = e.errno ++ else: ++ error_code = e[0] ++ ++ if error_code == errno.EINTR: ++ continue ++ raise