From 45fb66af8f4495355c2207ca8bc2991b446c71bf Mon Sep 17 00:00:00 2001 From: JCGoran Date: Wed, 11 Dec 2024 10:38:48 +0100 Subject: [PATCH] Replace `HocTopContext*` macros with class (#3279) --- src/nrnpython/hoccontext.h | 32 ++++++++++++++++++++------------ src/nrnpython/nrnpy_hoc.cpp | 20 ++++++-------------- src/nrnpython/nrnpy_p2h.cpp | 3 +-- src/nrnpython/nrnpython.cpp | 3 +-- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/nrnpython/hoccontext.h b/src/nrnpython/hoccontext.h index 85daea8fbe..0cb918fb1d 100644 --- a/src/nrnpython/hoccontext.h +++ b/src/nrnpython/hoccontext.h @@ -5,18 +5,6 @@ extern Objectdata* hoc_top_level_data; extern Symlist* hoc_top_level_symlist; extern Symlist* hoc_symlist; -#define HocTopContextSet \ - HocContext hcref; \ - HocContext* hc_ = 0; \ - if (hoc_thisobject) { \ - hc_ = hc_save_and_set_to_top_(&hcref); \ - } - -#define HocContextRestore \ - if (hc_) { \ - hc_restore_(hc_); \ - } - struct HocContext { Object* obj; Objectdata* obd; @@ -37,3 +25,23 @@ static void hc_restore_(HocContext* hc) { hoc_objectdata = hc->obd; hoc_symlist = hc->sl; } + +// RAII guard for the top HOC context +class HocTopContextManager { + private: + HocContext hcref; + HocContext* hc_ = nullptr; + + public: + HocTopContextManager() { + // ``hoc_thisobject`` is global + if (hoc_thisobject) { + hc_ = hc_save_and_set_to_top_(&hcref); + } + } + ~HocTopContextManager() { + if (hc_) { + hc_restore_(hc_); + } + } +}; diff --git a/src/nrnpython/nrnpy_hoc.cpp b/src/nrnpython/nrnpy_hoc.cpp index 0ee57d8289..0b6fbe819e 100644 --- a/src/nrnpython/nrnpy_hoc.cpp +++ b/src/nrnpython/nrnpy_hoc.cpp @@ -756,7 +756,7 @@ static void* fcall(void* vself, void* vargs) { return result; } else { - HocTopContextSet + auto interp = HocTopContextManager(); Inst fc[4]; // ugh. so a potential call of hoc_get_last_pointer_symbol will return nullptr. fc[0].in = STOP; @@ -766,7 +766,6 @@ static void* fcall(void* vself, void* vargs) { Inst* pcsav = save_pc(fc + 1); hoc_call(); hoc_pc = pcsav; - HocContextRestore; } return nrnpy_hoc_pop("laststatement fcall"); @@ -1263,7 +1262,7 @@ static PyObject* hocobj_getattr(PyObject* subself, PyObject* pyname) { } } // top level interpreter fork - HocTopContextSet + auto interp = HocTopContextManager(); switch (sym->type) { case VAR: // double* if (!is_array(*sym)) { @@ -1373,7 +1372,6 @@ static PyObject* hocobj_getattr(PyObject* subself, PyObject* pyname) { } } } - HocContextRestore return result.release().ptr(); } @@ -1499,7 +1497,7 @@ static int hocobj_setattro(PyObject* subself, PyObject* pyname, PyObject* value) return -1; } } - HocTopContextSet + auto interp = HocTopContextManager(); switch (sym->type) { case VAR: // double* if (is_array(*sym)) { @@ -1533,7 +1531,6 @@ static int hocobj_setattro(PyObject* subself, PyObject* pyname, PyObject* value) } else { hoc_pushs(sym); if (hoc_evalpointer_err()) { // not possible to raise error. - HocContextRestore; return -1; } err = PyArg_Parse(value, "d", hoc_pxpop()) == 0; @@ -1590,7 +1587,6 @@ static int hocobj_setattro(PyObject* subself, PyObject* pyname, PyObject* value) err = -1; break; } - HocContextRestore return err; } @@ -2009,14 +2005,13 @@ static PyObject* hocobj_getitem(PyObject* self, Py_ssize_t ix) { } } } else { // must be a top level intermediate - HocTopContextSet + auto interp = HocTopContextManager(); switch (po->sym_->type) { case VAR: hocobj_pushtop(po, po->sym_, ix); if (hoc_evalpointer_err()) { --po->nindex_; - HocContextRestore; - return NULL; + return nullptr; } --po->nindex_; if (po->type_ == PyHoc::HocArrayIncomplete) { @@ -2040,7 +2035,6 @@ static PyObject* hocobj_getitem(PyObject* self, Py_ssize_t ix) { --po->nindex_; break; } - HocContextRestore; } } return result.release().ptr(); @@ -2158,12 +2152,11 @@ static int hocobj_setitem(PyObject* self, Py_ssize_t i, PyObject* arg) { err = set_final_from_stk(arg); } } else { // must be a top level intermediate - HocTopContextSet + auto interp = HocTopContextManager(); switch (po->sym_->type) { case VAR: hocobj_pushtop(po, po->sym_, i); if (hoc_evalpointer_err()) { - HocContextRestore; --po->nindex_; return -1; } @@ -2194,7 +2187,6 @@ static int hocobj_setitem(PyObject* self, Py_ssize_t i, PyObject* arg) { PyErr_SetString(PyExc_TypeError, "not assignable"); break; } - HocContextRestore; } return err; } diff --git a/src/nrnpython/nrnpy_p2h.cpp b/src/nrnpython/nrnpy_p2h.cpp index d85aed2de7..b1ebd94e59 100644 --- a/src/nrnpython/nrnpy_p2h.cpp +++ b/src/nrnpython/nrnpy_p2h.cpp @@ -100,7 +100,7 @@ static nb::object nrnpy_pyCallObject(nb::callable callable, nb::object args) { // When hoc calls a PythonObject method, then in case python // calls something back in hoc, the hoc interpreter must be // at the top level - HocTopContextSet + auto interp = HocTopContextManager(); nb::tuple tup(args); nb::object p = nb::steal(PyObject_CallObject(callable.ptr(), tup.ptr())); #if 0 @@ -110,7 +110,6 @@ printf("\nargs\n"); PyObject_Print(args, stdout, 0); printf("\nreturn %p\n", p); #endif - HocContextRestore // It would be nice to handle the error here, ending with a hoc_execerror // for any Exception (note, that does not include SystemExit). However // since many, but not all, of the callers need to clean up and diff --git a/src/nrnpython/nrnpython.cpp b/src/nrnpython/nrnpython.cpp index d01dac4794..217679fca6 100644 --- a/src/nrnpython/nrnpython.cpp +++ b/src/nrnpython/nrnpython.cpp @@ -383,12 +383,11 @@ static int nrnpython_start(int b) { static void nrnpython_real() { int retval = 0; #if USE_PYTHON - HocTopContextSet { + auto interp = HocTopContextManager(); nanobind::gil_scoped_acquire lock{}; retval = (PyRun_SimpleString(hoc_gargstr(1)) == 0); } - HocContextRestore #endif hoc_retpushx(retval); }