diff options
author | Thouis (Ray) Jones <thouis@gmail.com> | 2012-06-18 11:50:28 +0200 |
---|---|---|
committer | Thouis (Ray) Jones <thouis@gmail.com> | 2012-06-18 11:50:28 +0200 |
commit | 5b5a0f4999dfac66c9c27160737352c727a3517b (patch) | |
tree | dad10b0b30aa85ecb6093fd1017bebd13fb1a159 /numpy | |
parent | 32370937a5692befe4971790cc0b71f72fe08bb1 (diff) | |
download | numpy-5b5a0f4999dfac66c9c27160737352c727a3517b.tar.gz |
Wrap hook functions with GIL, add example.
Wraps the SetHook and calls to the hook with the GIL, to prevent races.
Adds an example of using the interface for callbacks into python code.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 3917c1611..54e26c08f 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -3672,22 +3672,29 @@ NPY_NO_EXPORT void *_PyDataMem_eventhook_user_data; * Returns a pointer to the previous hook or NULL. If old_data is * non-NULL, the previous user_data pointer will be copied to it. * - * * If not NULL, hook will be called at the end of each PyDataMem_NEW/FREE/RENEW: * result = PyDataMem_NEW(size) -> (*hook)(NULL, result, size, user_data) * PyDataMem_FREE(ptr) -> (*hook)(ptr, NULL, 0, user_data) * result = PyDataMem_RENEW(ptr, size) -> (*hook)(ptr, result, size, user_data) + * + * When the hook is called, the GIL will be held by the calling + * thread. The hook should be written to be reentrant, if it performs + * operations that might cause new allocation events (such as the + * creation/descruction numpy objects, or creating/destroying Python + * objects which might cause a gc) */ NPY_NO_EXPORT PyDataMem_EventHookFunc * PyDataMem_SetEventHook(PyDataMem_EventHookFunc *newhook, void *user_data, void **old_data) { + PyGILState_STATE gilstate = PyGILState_Ensure(); PyDataMem_EventHookFunc *temp = _PyDataMem_eventhook; _PyDataMem_eventhook = newhook; if (old_data != NULL) { *old_data = _PyDataMem_eventhook_user_data; } _PyDataMem_eventhook_user_data = user_data; + PyGILState_Release(gilstate); return temp; } @@ -3701,8 +3708,12 @@ PyDataMem_NEW(size_t size) result = malloc(size); if (_PyDataMem_eventhook != NULL) { - (*_PyDataMem_eventhook)(NULL, result, size, - _PyDataMem_eventhook_user_data); + PyGILState_STATE gilstate = PyGILState_Ensure(); + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(NULL, result, size, + _PyDataMem_eventhook_user_data); + } + PyGILState_Release(gilstate); } return (char *)result; } @@ -3715,8 +3726,12 @@ PyDataMem_FREE(void *ptr) { free(ptr); if (_PyDataMem_eventhook != NULL) { - (*_PyDataMem_eventhook)(ptr, NULL, 0, - _PyDataMem_eventhook_user_data); + PyGILState_STATE gilstate = PyGILState_Ensure(); + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(ptr, NULL, 0, + _PyDataMem_eventhook_user_data); + } + PyGILState_Release(gilstate); } } @@ -3730,8 +3745,12 @@ PyDataMem_RENEW(void *ptr, size_t size) result = realloc(ptr, size); if (_PyDataMem_eventhook != NULL) { - (*_PyDataMem_eventhook)(ptr, result, size, - _PyDataMem_eventhook_user_data); + PyGILState_STATE gilstate = PyGILState_Ensure(); + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(ptr, result, size, + _PyDataMem_eventhook_user_data); + } + PyGILState_Release(gilstate); } return (char *)result; } |