author | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-05-22 04:24:03 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-05-22 04:24:03 UTC |
parent | 242a627f4da94ddfaa176b0a414e4d93bebeb5af |
.gitignore | +3 | -6 |
Makefile | +8 | -12 |
README | +2 | -1 |
bindings/{python3 => python}/fiu.py | +0 | -0 |
bindings/{python3 => python}/fiu_ll.c | +15 | -3 |
bindings/{python3 => python}/setup.py | +8 | -1 |
bindings/python2/fiu.py | +0 | -75 |
bindings/python2/fiu_ll.c | +0 | -191 |
bindings/python2/setup.py | +0 | -17 |
diff --git a/.gitignore b/.gitignore index 6680650..850b3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ -bindings/python2/build -bindings/python2/*.pyc -bindings/python2/*.pyo -bindings/python3/build -bindings/python3/*.pyc -bindings/python3/*.pyo +bindings/python/build +bindings/python/*.pyc +bindings/python/*.pyo libfiu/*.o libfiu/libfiu.a libfiu/libfiu.pc diff --git a/Makefile b/Makefile index f42608a..da76bf2 100644 --- a/Makefile +++ b/Makefile @@ -11,22 +11,19 @@ install: python2: - cd bindings/python2 && python setup.py build + cd bindings/python && python setup.py build python2_install: - cd bindings/python2 && python setup.py install - -python2_clean: - cd bindings/python2 && rm -rf build/ + cd bindings/python && python setup.py install python3: - cd bindings/python3 && python3 setup.py build + cd bindings/python && python3 setup.py build python3_install: - cd bindings/python3 && python3 setup.py install + cd bindings/python && python3 setup.py install -python3_clean: - cd bindings/python3 && rm -rf build/ +python_clean: + cd bindings/python && rm -rf build/ preload: @@ -35,13 +32,12 @@ preload: preload_clean: $(MAKE) -C preload clean -clean: python2_clean python3_clean +clean: python_clean $(MAKE) -C libfiu clean .PHONY: default all clean libfiu utils \ - python2 python2_install python2_clean \ - python3 python3_install python3_clean \ + python2 python2_install python3 python3_install python_clean \ preload preload_clean diff --git a/README b/README index 8ba4ef7..7e8cc80 100644 --- a/README +++ b/README @@ -31,7 +31,8 @@ for installing. By default it installs into /usr/local, but you can provide an alternative prefix by running "make PREFIX=/my/prefix install". To build the Python bindings, use "make python2"; to install them you can run -"make python2_install". +"make python2_install". For the Python 3 bindings, use "make python3" and +"make python3_install". Where to report bugs diff --git a/bindings/python3/fiu.py b/bindings/python/fiu.py similarity index 100% rename from bindings/python3/fiu.py rename to bindings/python/fiu.py diff --git a/bindings/python3/fiu_ll.c b/bindings/python/fiu_ll.c similarity index 93% rename from bindings/python3/fiu_ll.c rename to bindings/python/fiu_ll.c index cff30ed..59e3b16 100644 --- a/bindings/python3/fiu_ll.c +++ b/bindings/python/fiu_ll.c @@ -1,10 +1,11 @@ /* - * Python bindings for libfiu + * Python 2/3 bindings for libfiu * Alberto Bertogli (albertito@blitiri.com.ar) * * This is the low-level module, used by the python one to construct - * friendlier objects. + * friendlier objects. It support both Python 2 and 3, assuming the constants + * PYTHON2 and PYTHON3 are defined accordingly. */ #include <Python.h> @@ -178,24 +179,35 @@ static PyMethodDef fiu_methods[] = { { NULL } }; +#ifdef PYTHON3 static PyModuleDef fiu_module = { PyModuleDef_HEAD_INIT, .m_name = "libfiu", .m_size = -1, .m_methods = fiu_methods, }; +#endif - +#ifdef PYTHON2 +PyMODINIT_FUNC initfiu_ll(void) +#else PyMODINIT_FUNC PyInit_fiu_ll(void) +#endif { PyObject *m; +#ifdef PYTHON2 + m = Py_InitModule("fiu_ll", fiu_methods); +#else m = PyModule_Create(&fiu_module); +#endif PyModule_AddIntConstant(m, "FIU_ONETIME", FIU_ONETIME); fiu_init(0); +#ifdef PYTHON3 return m; +#endif } diff --git a/bindings/python3/setup.py b/bindings/python/setup.py similarity index 62% rename from bindings/python3/setup.py rename to bindings/python/setup.py index dbdc256..2255064 100644 --- a/bindings/python3/setup.py +++ b/bindings/python/setup.py @@ -1,9 +1,16 @@ +import sys from distutils.core import setup, Extension +if sys.version_info[0] == 2: + ver_define = ('PYTHON2', '1') +elif sys.version_info[0] == 3: + ver_define = ('PYTHON3', '1') + fiu_ll = Extension("fiu_ll", libraries = ['fiu'], - sources = ['fiu_ll.c']) + sources = ['fiu_ll.c'], + define_macros = [ver_define]) setup( name = 'fiu', diff --git a/bindings/python2/fiu.py b/bindings/python2/fiu.py deleted file mode 100644 index f4e6ece..0000000 --- a/bindings/python2/fiu.py +++ /dev/null @@ -1,75 +0,0 @@ - -""" -libfiu python wrapper - -This module is a wrapper for the libfiu, the fault injection C library. - -It provides an almost one-to-one mapping of the libfiu functions, although its -primary use is to be able to test C code from within Python. - -For fault injection in Python, a native library would be more suitable. - -See libfiu's manpage for more detailed documentation. -""" - -import fiu_ll as _ll - - -def fail(name): - "Returns the failure status of the given point of failure." - return _ll.fail(name) - -def failinfo(name): - """Returns the information associated with the last failure. Use with - care, can be fatal if the point of failure was not enabled via - Python.""" - return _ll.failinfo() - - -# To be sure failinfo doesn't dissapear from under our feet, we keep a -# name -> failinfo table. See fiu_ll's comments for more details. -_fi_table = {} - -def enable(name, failnum = 1, failinfo = None, flags = 0): - "Enables the given point of failure." - _fi_table[name] = failnum - r = _ll.enable(name, failnum, failinfo, flags) - if r != 0: - del _fi_table[name] - raise RuntimeError, r - -def enable_random(name, probability, failnum = 1, failinfo = None, flags = 0): - "Enables the given point of failure, with the given probability." - _fi_table[name] = failnum - r = _ll.enable_random(name, failnum, failinfo, flags, probability) - if r != 0: - del _fi_table[name] - raise RuntimeError, r - -def enable_external(name, cb, failnum = 1, flags = 0): - """Enables the given point of failure, leaving the decision whether to - fail or not to the given external function, which should return 0 if - it is not to fail, or 1 otherwise. - - The cb parameter is a Python function that takes three parameters, - name, failnum and flags, with the same values that we receive. - - For technical limitations, enable_external() cannot take - failinfo.""" - # in this case, use the table to prevent the function from - # dissapearing - _fi_table[name] = cb - r = _ll.enable_external(name, failnum, flags, cb) - if r != 0: - raise RuntimeError, r - -def disable(name): - """Disables the given point of failure, undoing the actions of the - enable*() functions.""" - if name in _fi_table: - del _fi_table[name] - r = _ll.disable(name) - if r != 0: - raise RuntimeError, r - - diff --git a/bindings/python2/fiu_ll.c b/bindings/python2/fiu_ll.c deleted file mode 100644 index f0c9a49..0000000 --- a/bindings/python2/fiu_ll.c +++ /dev/null @@ -1,191 +0,0 @@ - -/* - * Python bindings for libfiu - * Alberto Bertogli (albertito@blitiri.com.ar) - * - * This is the low-level module, used by the python one to construct - * friendlier objects. - */ - -#include <Python.h> - -/* Unconditionally enable fiu, otherwise we get fake headers */ -#define FIU_ENABLE 1 - -#include <fiu.h> -#include <fiu-control.h> - - -static PyObject *fail(PyObject *self, PyObject *args) -{ - char *name; - PyObject *rv, *err; - - if (!PyArg_ParseTuple(args, "s:fail", &name)) - return NULL; - - rv = PyLong_FromLong(fiu_fail(name)); - err = PyErr_Occurred(); - - if (rv == NULL || err != NULL) { - Py_XDECREF(rv); - return NULL; - } - - return rv; -} - -static PyObject *failinfo(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, ":failinfo")) - return NULL; - - /* We assume failinfo is a python object; but the caller must be - * careful because if it's not, it can get into trouble. - * Note that we DO NOT TOUCH THE RC OF THE OBJECT. It's entirely up to - * the caller to make sure it's still alive. */ - return (PyObject *) fiu_failinfo(); -} - -static PyObject *enable(PyObject *self, PyObject *args) -{ - char *name; - int failnum; - PyObject *failinfo; - unsigned int flags; - - if (!PyArg_ParseTuple(args, "siOI:enable", &name, &failnum, &failinfo, - &flags)) - return NULL; - - /* See failinfo()'s comment regarding failinfo's RC */ - return PyLong_FromLong(fiu_enable(name, failnum, failinfo, flags)); -} - -static PyObject *enable_random(PyObject *self, PyObject *args) -{ - char *name; - int failnum; - PyObject *failinfo; - unsigned int flags; - double probability; - - if (!PyArg_ParseTuple(args, "siOId:enable_random", &name, &failnum, - &failinfo, &flags, &probability)) - return NULL; - - /* See failinfo()'s comment regarding failinfo's RC */ - return PyLong_FromLong(fiu_enable_random(name, failnum, failinfo, - flags, probability)); -} - - -static int external_callback(const char *name, int *failnum, void **failinfo, - unsigned int *flags) -{ - int rv; - PyObject *cbrv; - PyObject *args; - PyGILState_STATE gil_state; - - /* We need to protect ourselves from the following case: - * - fiu.enable_callback('x', cb) (where cb is obviously a Python - * function) - * - Later on, call a function p1() inside a python C module, that - * runs a C function c1() inside - * Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS - * - c1() calls fiu_fail("x") - * - fiu_fail("x") calls external_callback(), and it should run cb() - * - BUT! It can't run cb(), because it's inside - * Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS so it's not safe to - * execute any Python code! - * - * The solution is to ensure we're safe to run Python code using - * PyGILState_Ensure()/PyGILState_Release(). - */ - - gil_state = PyGILState_Ensure(); - args = Py_BuildValue("(siI)", name, *failnum, *flags); - if (args == NULL) { - PyGILState_Release(gil_state); - return 0; - } - - cbrv = PyEval_CallObject(*failinfo, args); - Py_DECREF(args); - - if (cbrv == NULL) { - PyGILState_Release(gil_state); - return 0; - } - - /* If PyInt_AsLong() causes an error, it will be handled by the - * PyErr_Occurred() check in fail(), so we don't need to worry about - * it now. */ - rv = PyInt_AsLong(cbrv); - Py_DECREF(cbrv); - - PyGILState_Release(gil_state); - - return rv; -} - -static PyObject *enable_external(PyObject *self, PyObject *args) -{ - char *name; - int failnum; - unsigned int flags; - PyObject *py_external_cb; - - if (!PyArg_ParseTuple(args, "siIO:enable_random", &name, &failnum, - &flags, &py_external_cb)) - return NULL; - - if (!PyCallable_Check(py_external_cb)) { - PyErr_SetString(PyExc_TypeError, "parameter must be callable"); - return NULL; - } - - /* We use failinfo to store Python's callback function. It'd be nice - * if we could keep both, but it's not easy without keeping state - * inside the C module. - * - * Similar to the way failinfo is handled, we DO NOT TOUCH THE RC OF - * THE EXTERNAL CALLBACK, assuming the caller will take care of making - * sure it doesn't dissapear from beneath us. */ - return PyLong_FromLong(fiu_enable_external(name, failnum, - py_external_cb, flags, external_callback)); -} - -static PyObject *disable(PyObject *self, PyObject *args) -{ - char *name; - - if (!PyArg_ParseTuple(args, "s:fail", &name)) - return NULL; - - return PyLong_FromLong(fiu_disable(name)); -} - - -static PyMethodDef fiu_functions[] = { - { "fail", (PyCFunction) fail, METH_VARARGS, NULL }, - { "failinfo", (PyCFunction) failinfo, METH_VARARGS, NULL }, - { "enable", (PyCFunction) enable, METH_VARARGS, NULL }, - { "enable_random", (PyCFunction) enable_random, METH_VARARGS, NULL }, - { "enable_external", (PyCFunction) enable_external, METH_VARARGS, NULL }, - { "disable", (PyCFunction) disable, METH_VARARGS, NULL }, - { NULL } -}; - -PyMODINIT_FUNC initfiu_ll(void) -{ - PyObject *m; - - m = Py_InitModule("fiu_ll", fiu_functions); - - PyModule_AddIntConstant(m, "FIU_ONETIME", FIU_ONETIME); - - fiu_init(0); -} - diff --git a/bindings/python2/setup.py b/bindings/python2/setup.py deleted file mode 100644 index dbdc256..0000000 --- a/bindings/python2/setup.py +++ /dev/null @@ -1,17 +0,0 @@ - -from distutils.core import setup, Extension - -fiu_ll = Extension("fiu_ll", - libraries = ['fiu'], - sources = ['fiu_ll.c']) - -setup( - name = 'fiu', - description = "libfiu bindings", - author = "Alberto Bertogli", - author_email = "albertito@blitiri.com.ar", - url = "http://blitiri.com.ar/p/libfiu", - py_modules = ['fiu'], - ext_modules = [fiu_ll] -) -