pytevent improvements & Python 3 port
Petr Viktorin
pviktori at redhat.com
Tue May 26 06:07:45 MDT 2015
Hello,
The first patch is a fix for a bug in the buildsystem changes for py3.
(It only occurs when building for two Pythons, so Samba is safe.)
I've played a bit with the pytevent wrapper, and found that the types
for timers and FDs are not defined, so, for example, trying to print
them out segfaults:
>>> import tevent
>>> ctx = tevent.Context()
>>> timer = ctx.add_timer(0, lambda t: None)
>>> timer
Segmentation fault (core dumped)
I'm sending a quick fix for FDs, and a more comprehensive one for timers.
Also, "Context.add_timer" requires passing a struct timeval cast to a
long inside a Python integer, which is very hard to do portably from
Python. I've added "add_timer_offset", which takes a number of seconds
from now.
I've also ported pytevent to Python 3. The library doesn't deal with
strings much, so the port is trivial.
--
Petr Viktorin
-------------- next part --------------
From 7fc58897bb6d506790f515233b9aeba03c8f17cc Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 22 May 2015 13:06:48 +0200
Subject: [PATCH 1/6] buildtools: Always reset the build environment
In install_library, the Build object's environment was not reset
after an early return, so the extrapython env would be used in
subsequent build steps.
Wrap everything in a try-finally block to make sure the env is reset.
(Almost all of the change is indentation, `git show -w` recommended.)
Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
buildtools/wafsamba/samba_install.py | 163 ++++++++++++++++++-----------------
1 file changed, 82 insertions(+), 81 deletions(-)
diff --git a/buildtools/wafsamba/samba_install.py b/buildtools/wafsamba/samba_install.py
index af8d2ad..3d0c23a 100644
--- a/buildtools/wafsamba/samba_install.py
+++ b/buildtools/wafsamba/samba_install.py
@@ -60,95 +60,96 @@ def install_library(self):
bld = self.bld
default_env = bld.all_envs['default']
- if self.env['IS_EXTRA_PYTHON']:
- bld.all_envs['default'] = bld.all_envs['extrapython']
+ try:
+ if self.env['IS_EXTRA_PYTHON']:
+ bld.all_envs['default'] = bld.all_envs['extrapython']
- install_ldflags = install_rpath(self)
- build_ldflags = build_rpath(bld)
+ install_ldflags = install_rpath(self)
+ build_ldflags = build_rpath(bld)
- if not Options.is_install or not getattr(self, 'samba_install', True):
- # just need to set the build rpath if we are not installing
- self.env.RPATH = build_ldflags
- return
+ if not Options.is_install or not getattr(self, 'samba_install', True):
+ # just need to set the build rpath if we are not installing
+ self.env.RPATH = build_ldflags
+ return
- # setup the install path, expanding variables
- install_path = getattr(self, 'samba_inst_path', None)
- if install_path is None:
- if getattr(self, 'private_library', False):
- install_path = '${PRIVATELIBDIR}'
+ # setup the install path, expanding variables
+ install_path = getattr(self, 'samba_inst_path', None)
+ if install_path is None:
+ if getattr(self, 'private_library', False):
+ install_path = '${PRIVATELIBDIR}'
+ else:
+ install_path = '${LIBDIR}'
+ install_path = bld.EXPAND_VARIABLES(install_path)
+
+ target_name = self.target
+
+ if install_ldflags != build_ldflags:
+ # we will be creating a new target name, and using that for the
+ # install link. That stops us from overwriting the existing build
+ # target, which has different ldflags
+ self.done_install_library = True
+ t = self.clone(self.env)
+ t.posted = False
+ t.target += '.inst'
+ self.env.RPATH = build_ldflags
else:
- install_path = '${LIBDIR}'
- install_path = bld.EXPAND_VARIABLES(install_path)
-
- target_name = self.target
-
- if install_ldflags != build_ldflags:
- # we will be creating a new target name, and using that for the
- # install link. That stops us from overwriting the existing build
- # target, which has different ldflags
- self.done_install_library = True
- t = self.clone(self.env)
- t.posted = False
- t.target += '.inst'
- self.env.RPATH = build_ldflags
- else:
- t = self
-
- t.env.RPATH = install_ldflags
-
- dev_link = None
-
- # in the following the names are:
- # - inst_name is the name with .inst. in it, in the build
- # directory
- # - install_name is the name in the install directory
- # - install_link is a symlink in the install directory, to install_name
-
- if getattr(self, 'samba_realname', None):
- install_name = self.samba_realname
- install_link = None
- if getattr(self, 'soname', ''):
+ t = self
+
+ t.env.RPATH = install_ldflags
+
+ dev_link = None
+
+ # in the following the names are:
+ # - inst_name is the name with .inst. in it, in the build
+ # directory
+ # - install_name is the name in the install directory
+ # - install_link is a symlink in the install directory, to install_name
+
+ if getattr(self, 'samba_realname', None):
+ install_name = self.samba_realname
+ install_link = None
+ if getattr(self, 'soname', ''):
+ install_link = self.soname
+ if getattr(self, 'samba_type', None) == 'PYTHON':
+ inst_name = bld.make_libname(t.target, nolibprefix=True, python=True)
+ else:
+ inst_name = bld.make_libname(t.target)
+ elif self.vnum:
+ vnum_base = self.vnum.split('.')[0]
+ install_name = bld.make_libname(target_name, version=self.vnum)
+ install_link = bld.make_libname(target_name, version=vnum_base)
+ inst_name = bld.make_libname(t.target)
+ if not self.private_library:
+ # only generate the dev link for non-bundled libs
+ dev_link = bld.make_libname(target_name)
+ elif getattr(self, 'soname', ''):
+ install_name = bld.make_libname(target_name)
install_link = self.soname
- if getattr(self, 'samba_type', None) == 'PYTHON':
- inst_name = bld.make_libname(t.target, nolibprefix=True, python=True)
- else:
inst_name = bld.make_libname(t.target)
- elif self.vnum:
- vnum_base = self.vnum.split('.')[0]
- install_name = bld.make_libname(target_name, version=self.vnum)
- install_link = bld.make_libname(target_name, version=vnum_base)
- inst_name = bld.make_libname(t.target)
- if not self.private_library:
- # only generate the dev link for non-bundled libs
- dev_link = bld.make_libname(target_name)
- elif getattr(self, 'soname', ''):
- install_name = bld.make_libname(target_name)
- install_link = self.soname
- inst_name = bld.make_libname(t.target)
- else:
- install_name = bld.make_libname(target_name)
- install_link = None
- inst_name = bld.make_libname(t.target)
-
- if t.env.SONAME_ST:
- # ensure we get the right names in the library
- if install_link:
- t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
else:
- t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
- t.env.SONAME_ST = ''
-
- # tell waf to install the library
- bld.install_as(os.path.join(install_path, install_name),
- os.path.join(self.path.abspath(bld.env), inst_name),
- chmod=MODE_755)
- if install_link and install_link != install_name:
- # and the symlink if needed
- bld.symlink_as(os.path.join(install_path, install_link), os.path.basename(install_name))
- if dev_link:
- bld.symlink_as(os.path.join(install_path, dev_link), os.path.basename(install_name))
+ install_name = bld.make_libname(target_name)
+ install_link = None
+ inst_name = bld.make_libname(t.target)
- bld.all_envs['default'] = default_env
+ if t.env.SONAME_ST:
+ # ensure we get the right names in the library
+ if install_link:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
+ else:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
+ t.env.SONAME_ST = ''
+
+ # tell waf to install the library
+ bld.install_as(os.path.join(install_path, install_name),
+ os.path.join(self.path.abspath(bld.env), inst_name),
+ chmod=MODE_755)
+ if install_link and install_link != install_name:
+ # and the symlink if needed
+ bld.symlink_as(os.path.join(install_path, install_link), os.path.basename(install_name))
+ if dev_link:
+ bld.symlink_as(os.path.join(install_path, dev_link), os.path.basename(install_name))
+ finally:
+ bld.all_envs['default'] = default_env
@feature('cshlib')
--
2.1.0
From 17a459af8959091ea7c705d998322ae74d50aa20 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Thu, 4 Dec 2014 12:44:56 +0100
Subject: [PATCH 2/6] pytevent: Better error and reference handling
py_backend_list:
- Handle cases of PyString_FromString or PyList_Append failing.
- Properly decrease the reference count of the returned strings.
py_register_backend:
- Decref "name" after use
Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
lib/tevent/pytevent.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/lib/tevent/pytevent.c b/lib/tevent/pytevent.c
index af3f9d6..4de0e3d 100644
--- a/lib/tevent/pytevent.c
+++ b/lib/tevent/pytevent.c
@@ -177,14 +177,18 @@ static PyObject *py_register_backend(PyObject *self, PyObject *args)
if (!PyString_Check(name)) {
PyErr_SetNone(PyExc_TypeError);
+ Py_DECREF(name);
return NULL;
}
if (!tevent_register_backend(PyString_AsString(name), &py_tevent_ops)) { /* FIXME: What to do with backend */
PyErr_SetNone(PyExc_RuntimeError);
+ Py_DECREF(name);
return NULL;
}
+ Py_DECREF(name);
+
Py_RETURN_NONE;
}
@@ -684,9 +688,10 @@ static PyObject *py_set_default_backend(PyObject *self, PyObject *args)
static PyObject *py_backend_list(PyObject *self)
{
- PyObject *ret;
- int i;
- const char **backends;
+ PyObject *ret = NULL;
+ PyObject *string = NULL;
+ int i, result;
+ const char **backends = NULL;
ret = PyList_New(0);
if (ret == NULL) {
@@ -696,16 +701,30 @@ static PyObject *py_backend_list(PyObject *self)
backends = tevent_backend_list(NULL);
if (backends == NULL) {
PyErr_SetNone(PyExc_RuntimeError);
- Py_DECREF(ret);
- return NULL;
+ goto err;
}
for (i = 0; backends[i]; i++) {
- PyList_Append(ret, PyString_FromString(backends[i]));
+ string = PyString_FromString(backends[i]);
+ if (!string) {
+ goto err;
+ }
+ result = PyList_Append(ret, string);
+ if (result) {
+ goto err;
+ }
+ Py_DECREF(string);
+ string = NULL;
}
talloc_free(backends);
return ret;
+
+err:
+ Py_XDECREF(ret);
+ Py_XDECREF(string);
+ talloc_free(backends);
+ return NULL;
}
static PyMethodDef tevent_methods[] = {
--
2.1.0
From 82425014c65442f3916358301f770b927dfd5e1e Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 22 May 2015 13:29:11 +0200
Subject: [PATCH 3/6] pytevent: Define missing TeventFd_Type object
The type objects for Fd was declared but never defined,
resulting in segfaults when it was used.
Define it.
Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
lib/tevent/pytevent.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/lib/tevent/pytevent.c b/lib/tevent/pytevent.c
index 4de0e3d..a495da5 100644
--- a/lib/tevent/pytevent.c
+++ b/lib/tevent/pytevent.c
@@ -415,6 +415,19 @@ static void py_fd_handler(struct tevent_context *ev,
Py_XDECREF(ret);
}
+static void py_tevent_fp_dealloc(TeventFd_Object *self)
+{
+ talloc_free(self->fd);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventFd_Type = {
+ .tp_name = "tevent.Fd",
+ .tp_basicsize = sizeof(TeventFd_Object),
+ .tp_dealloc = (destructor)py_tevent_fp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
{
int fd, flags;
--
2.1.0
From d2859d6030b6929caac710a03c0310041f1e8084 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Tue, 26 May 2015 13:25:12 +0200
Subject: [PATCH 4/6] pytalloc: Improve timer wrapper, and test it
Using Context.add_timer resulted in crashes due to missing type object
and bad reference