diff options
author | Travis Oliphant <oliphant@enthought.com> | 2006-08-24 08:36:48 +0000 |
---|---|---|
committer | Travis Oliphant <oliphant@enthought.com> | 2006-08-24 08:36:48 +0000 |
commit | ca059fbcebb498f68ccf5eecd692b4c90a6b4bb7 (patch) | |
tree | f63a853fab72bb5f9146a55a1c71951c5fb74eac | |
parent | 9ab77ec1e9fdd2ebe5dfe2eccd7ad129189ea076 (diff) | |
download | numpy-ca059fbcebb498f68ccf5eecd692b4c90a6b4bb7.tar.gz |
Add rudimentary interrupt handliNG. Add max, min, round, abs to the numpy space.
-rw-r--r-- | numpy/core/code_generators/generate_array_api.py | 1 | ||||
-rw-r--r-- | numpy/core/fromnumeric.py | 6 | ||||
-rw-r--r-- | numpy/core/include/numpy/ndarrayobject.h | 1 | ||||
-rw-r--r-- | numpy/core/include/numpy/npy_interrupt.h | 106 | ||||
-rw-r--r-- | numpy/core/ma.py | 1 | ||||
-rw-r--r-- | numpy/core/numeric.py | 2 | ||||
-rw-r--r-- | numpy/core/src/arraymethods.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarraymodule.c | 30 |
8 files changed, 99 insertions, 52 deletions
diff --git a/numpy/core/code_generators/generate_array_api.py b/numpy/core/code_generators/generate_array_api.py index 5213affb7..41c876963 100644 --- a/numpy/core/code_generators/generate_array_api.py +++ b/numpy/core/code_generators/generate_array_api.py @@ -20,6 +20,7 @@ typedef struct { npy_bool obval; } PyBoolScalarObject; + static unsigned int PyArray_GetNDArrayCVersion (void); static PyTypeObject PyBigArray_Type; static PyTypeObject PyArray_Type; diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index 6dacdbf52..77123c780 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -379,6 +379,8 @@ def amax(a, axis=None, out=None): return _wrapit(a, 'max', axis, out) return amax(axis, out) +max = amax + def amin(a, axis=None, out=None): """Return the minimum of a along dimension axis. """ @@ -388,6 +390,8 @@ def amin(a, axis=None, out=None): return _wrapit(a, 'min', axis, out) return amin(axis, out) +min = amin + def alen(a): """Return the length of a Python object interpreted as an array of at least 1 dimension. @@ -458,6 +462,8 @@ def round_(a, decimals=0, out=None): around = round_ +round = round_ + def mean(a, axis=None, dtype=None, out=None): """mean(a, axis=None, dtype=None) Return the arithmetic mean. diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h index 9551cd7bc..4d5719949 100644 --- a/numpy/core/include/numpy/ndarrayobject.h +++ b/numpy/core/include/numpy/ndarrayobject.h @@ -1384,6 +1384,7 @@ typedef struct { does not have ARR_HAS_DESCR flag set) */ } PyArrayInterface; + /* Includes the "function" C-API -- these are all stored in a list of pointers --- one for each file The two lists are concatenated into one in multiarray. diff --git a/numpy/core/include/numpy/npy_interrupt.h b/numpy/core/include/numpy/npy_interrupt.h index 0fd94cf34..d288185d8 100644 --- a/numpy/core/include/numpy/npy_interrupt.h +++ b/numpy/core/include/numpy/npy_interrupt.h @@ -10,8 +10,8 @@ SIGINT, SIGABRT, SIGALRM, SIGSEGV ****Warning*************** Do not allow code that creates temporary memory or increases reference -counts of Python objects to be interrupted unless you handle decrementing -the reference counts and freeing any allocated memory in the clean-up code. +counts of Python objects to be interrupted unless you handle it +differently. ************************** @@ -21,7 +21,7 @@ The mechanism for handling interrupts is conceptually simple: and store the old one. - run the code to be interrupted -- if an interrupt occurs the handler should basically just cause a return to the - calling function for clean-up work. + calling function for finish work. - restore the old signal handler Of course, every code that allows interrupts must account for @@ -32,74 +32,90 @@ factors. 1) platform portability (i.e. Microsoft says not to use longjmp to return from signal handling. They have a __try and __except extension to C instead but what about mingw?). - 2) how to handle threads - a) apparently whether signals are delivered to every thread of - the process or the "invoking" thread is platform dependent. - b) if we use global variables to save state, then how is this - to be done in a thread-safe way. - 3) A general-purpose facility must allow for the possibility of - re-entrance (i.e. during execution of the code that is allowed - to interrupt, we might call back into this very section of code - serially). + + 2) how to handle threads: apparently whether signals are delivered to + every thread of the process or the "invoking" thread is platform + dependent. --- we don't handle threads for now. + + 3) do we need to worry about re-entrance. For now, assume the + code will not call-back into itself. Ideas: 1) Start by implementing an approach that works on platforms that can use setjmp and longjmp functionality and does nothing - on other platforms. Initially only catch SIGINT. + on other platforms. - 2) Handle threads by storing global information in a linked-list - with a process-id key. Then use a call-back function that longjmps - only to the correct buffer. + 2) Ignore threads --- i.e. do not mix interrupt handling and threads - 3) Store a local copy of the global information and restore it on clean-up - so that re-entrance works. + 3) Add a default signal_handler function to the C-API but have the rest + use macros. -Interface: +Simple Interface: -In your C-extension. around a block of code you want to be interruptable -NPY_SIG_TRY { -[code] -} -NPY_SIG_EXCEPT(sigval) { -[signal return] -} -NPY_SIG_ELSE -[normal return] +In your C-extension: around a block of code you want to be interruptable +with a SIGINT -sigval is a local variable that will receive what -signal was received. You can use it to perform different -actions based on the signal received. +NPY_SIGINT_ON +[code] +NPY_SIGINT_OFF -Default actions (setting of specific Python errors) -can be obtained with +In order for this to work correctly, the +[code] block must not allocate any memory or alter the reference count of any +Python objects. In other words [code] must be interruptible so that continuation +after NPY_SIGINT_OFF will only be "missing some computations" -NPY_SIG_TRY { -[code] -NPY_SIG_EXCEPT_GOTO(label) -[normal return] +Interrupt handling does not work well with threads. -label: - [error return] */ /* Add signal handling macros */ #ifndef NPY_INTERRUPT_H #define NPY_INTERRUPT_H + +#ifndef NPY_NO_SIGNAL -#ifdef NPY_NO_SIGNAL +#ifndef sigsetjmp -#define NPY_SIG_ON -#define NPY_SIG_OFF +#define SIGSETJMP(arg1, arg2) setjmp(arg1) +#define SIGLONGJMP(arg1, arg2) longjmp(arg1, arg2) +#define SIGJMP_BUF jmp_buf #else -#define NPY_SIG_ON -#define NPY_SIG_OFF +#define SIGSETJMP(arg1, arg2) sigsetjmp(arg1, arg2) +#define SIGLONGJMP(arg1, arg2) siglongjmp(arg1, arg2) +#define SIGJMP_BUF sigjmp_buf + +#endif + +SIGJMP_BUF _NPY_SIGINT_BUF; + +static void +_npy_sighandler(int signum) +{ + PyOS_setsig(signum, SIG_IGN); + SIGLONGJMP(_NPY_SIGINT_BUF, signum); +} + + +# define NPY_SIGINT_ON { \ + PyOS_sighandler_t _npy_sig_save; \ + _npy_sig_save = PyOS_setsig(SIGINT, _npy_sighandler); \ + if (SIGSETJMP(_NPY_SIGINT_BUF, 1) == 0) { \ + +# define NPY_SIGINT_OFF } \ + PyOS_setsig(SIGINT, _npy_sig_save); \ + } + +#else /* NPY_NO_SIGNAL */ + +# define NPY_SIGINT_ON +# define NPY_SIGINT_OFF -#endif /* NPY_NO_SIGNAL */ +#endif /* HAVE_SIGSETJMP */ #endif /* NPY_INTERRUPT_H */ diff --git a/numpy/core/ma.py b/numpy/core/ma.py index 495764ae8..2e2d3f8ec 100644 --- a/numpy/core/ma.py +++ b/numpy/core/ma.py @@ -2144,7 +2144,6 @@ def _m(f): return MethodType(f, None, array) def not_implemented(*args, **kwds): raise NotImplementedError, "not yet implemented for numpy.ma arrays" -array.abs = array.__abs__ array.all = _m(alltrue) array.any = _m(sometrue) array.argmax = _m(argmax) diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index b28d13bde..b77fed3db 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -95,6 +95,8 @@ def extend_all(module): extend_all(umath) extend_all(numerictypes) +abs = absolute + newaxis = None ndarray = multiarray.ndarray diff --git a/numpy/core/src/arraymethods.c b/numpy/core/src/arraymethods.c index 8f7bce20d..9cbe5b455 100644 --- a/numpy/core/src/arraymethods.c +++ b/numpy/core/src/arraymethods.c @@ -252,8 +252,6 @@ array_min(PyArrayObject *self, PyObject *args, PyObject *kwds) return PyArray_Min(self, axis, out); } -static char doc_abs[] = "a.abs() returns abs(a)"; - static char doc_swapaxes[] = "a.swapaxes(axis1, axis2) returns new view with axes swapped."; static PyObject * @@ -1808,8 +1806,6 @@ static PyMethodDef array_methods[] = { METH_VARARGS|METH_KEYWORDS, doc_min}, {"ptp", (PyCFunction)array_ptp, METH_VARARGS|METH_KEYWORDS, doc_ptp}, - {"abs", (PyCFunction)array_absolute, - METH_VARARGS, doc_abs}, {"mean", (PyCFunction)array_mean, METH_VARARGS|METH_KEYWORDS, doc_mean}, {"trace", (PyCFunction)array_trace, diff --git a/numpy/core/src/multiarraymodule.c b/numpy/core/src/multiarraymodule.c index bbe2bd893..99f1e9684 100644 --- a/numpy/core/src/multiarraymodule.c +++ b/numpy/core/src/multiarraymodule.c @@ -21,7 +21,8 @@ */ #define _MULTIARRAYMODULE -#include "numpy/noprefix.h" +#define NPY_NO_PREFIX +#include "numpy/arrayobject.h" #define PyAO PyArrayObject @@ -931,6 +932,10 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o return ret; } +/* Why doesn't this just call the ufunc? + All we need to do is add it to the list of needed ufuncs. + */ + /*MULTIARRAY_API Conjugate */ @@ -6427,6 +6432,24 @@ compare_chararrays(PyObject *dummy, PyObject *args, PyObject *kwds) +#ifndef NPY_NO_SIGNAL + +static PyObject * +test_interrupt(PyObject *self) +{ + int a = 0; + NPY_SIGINT_ON + + while(1) { + a += 1; + } + + NPY_SIGINT_OFF + + return PyInt_FromLong(a); +} +#endif + static struct PyMethodDef array_module_methods[] = { {"_get_ndarray_c_version", (PyCFunction)array__get_ndarray_c_version, METH_VARARGS|METH_KEYWORDS, NULL}, @@ -6481,6 +6504,10 @@ static struct PyMethodDef array_module_methods[] = { METH_VARARGS | METH_KEYWORDS, NULL}, {"compare_chararrays", (PyCFunction)compare_chararrays, METH_VARARGS | METH_KEYWORDS, NULL}, +#ifndef NPY_NO_SIGNAL + {"test_interrupt", (PyCFunction)test_interrupt, + METH_NOARGS, NULL}, +#endif {NULL, NULL, 0} /* sentinel */ }; @@ -6680,7 +6707,6 @@ PyMODINIT_FUNC initmultiarray(void) { return; c_api = PyCObject_FromVoidPtr((void *)PyArray_API, NULL); - if (PyErr_Occurred()) goto err; PyDict_SetItemString(d, "_ARRAY_API", c_api); Py_DECREF(c_api); if (PyErr_Occurred()) goto err; |