Skip to content

Instantly share code, notes, and snippets.

@rgommers
Created July 17, 2024 19:54
Show Gist options
  • Save rgommers/7c722bfd79c48753900d86668884faf6 to your computer and use it in GitHub Desktop.
Save rgommers/7c722bfd79c48753900d86668884faf6 to your computer and use it in GitHub Desktop.
f2py snippet for a LAPACK function with a callback
/******************* See f2py2e/cb_rules.py: buildcallback *******************/
/********************* cb_cselect_in_gees__user__routines *********************/
typedef struct {
PyObject *capi;
PyTupleObject *args_capi;
int nofargs;
jmp_buf jmpbuf;
} cb_cselect_in_gees__user__routines_t;
#if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
static F2PY_THREAD_LOCAL_DECL cb_cselect_in_gees__user__routines_t *_active_cb_cselect_in_gees__user__routines = NULL;
static cb_cselect_in_gees__user__routines_t *swap_active_cb_cselect_in_gees__user__routines(cb_cselect_in_gees__user__routines_t *ptr) {
cb_cselect_in_gees__user__routines_t *prev = _active_cb_cselect_in_gees__user__routines;
_active_cb_cselect_in_gees__user__routines = ptr;
return prev;
}
static cb_cselect_in_gees__user__routines_t *get_active_cb_cselect_in_gees__user__routines(void) {
return _active_cb_cselect_in_gees__user__routines;
}
#else
static cb_cselect_in_gees__user__routines_t *swap_active_cb_cselect_in_gees__user__routines(cb_cselect_in_gees__user__routines_t *ptr) {
char *key = "__f2py_cb_cb_cselect_in_gees__user__routines";
return (cb_cselect_in_gees__user__routines_t *)F2PySwapThreadLocalCallbackPtr(key, ptr);
}
static cb_cselect_in_gees__user__routines_t *get_active_cb_cselect_in_gees__user__routines(void) {
char *key = "__f2py_cb_cb_cselect_in_gees__user__routines";
return (cb_cselect_in_gees__user__routines_t *)F2PyGetThreadLocalCallbackPtr(key);
}
#endif
@rgommers
Copy link
Author

Thread-local define:

#ifndef F2PY_THREAD_LOCAL_DECL
#if defined(_MSC_VER)
#define F2PY_THREAD_LOCAL_DECL __declspec(thread)
#elif defined(NPY_OS_MINGW)
#define F2PY_THREAD_LOCAL_DECL __thread
#elif defined(__STDC_VERSION__) \
      && (__STDC_VERSION__ >= 201112L) \
      && !defined(__STDC_NO_THREADS__) \
      && (!defined(__GLIBC__) || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 12)) \
      && !defined(NPY_OS_OPENBSD) && !defined(NPY_OS_HAIKU)
/* __STDC_NO_THREADS__ was first defined in a maintenance release of glibc 2.12,
   see https://lists.gnu.org/archive/html/commit-hurd/2012-07/msg00180.html,
   so `!defined(__STDC_NO_THREADS__)` may give false positive for the existence
   of `threads.h` when using an older release of glibc 2.12
   See gh-19437 for details on OpenBSD */
#include <threads.h>
#define F2PY_THREAD_LOCAL_DECL thread_local
#elif defined(__GNUC__) \
      && (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)))
#define F2PY_THREAD_LOCAL_DECL __thread
#endif
#endif

@rgommers
Copy link
Author

F2PY_USE_PYTHON_TLS is an old CLI option that I don't think is in use anymore.

@rgommers
Copy link
Author

Also the error handling may need to be looked at more closely, since it uses a global

static PyObject *_flapack_error;

which is modified from within functions.

@ngoldbaum
Copy link

The static pyobjects are fine since they refer to global objects that are read-only after module initialization.

@ngoldbaum
Copy link

ngoldbaum commented Jul 17, 2024

F2PySwapThreadLocalCallbackPtr uses the PyThreadState C API to implement thread-local state if it can't do it using the low-level thread local C declaration modifier.

The actual definition of F2PY_THREAD_LOCAL_DECL seems reasonable. We also check for _Thread_local in NumPy but I doubt it matters much for this use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment