diff --git a/coreneuron/io/nrn_setup.cpp b/coreneuron/io/nrn_setup.cpp index 6be380dee..f3e24ec2d 100644 --- a/coreneuron/io/nrn_setup.cpp +++ b/coreneuron/io/nrn_setup.cpp @@ -985,11 +985,34 @@ inline void mech_layout(FileHandler& F, T* data, int cnt, int sz, int layout) { } } +/** + * Cleanup global ion map created during mechanism registration + * + * In case of coreneuron standalone execution nrn_ion_global_map + * can be deleted at the end of execution. But in case embedded + * run via neuron, mechanisms are registered only once i.e. during + * first call to coreneuron. This is why we call cleanup only in + * case of standalone coreneuron execution via nrniv-core or + * special-core. + * + * @todo coreneuron should have finalise callback which can be + * called from NEURON for final memory cleanup including global + * state like registered mechanisms and ions map. + */ +void nrn_cleanup_ion_map() { + for (int i = 0; i < nrn_ion_global_map_size; i++) { + free_memory(nrn_ion_global_map[i]); + } + free_memory(nrn_ion_global_map); + nrn_ion_global_map = nullptr; + nrn_ion_global_map_size = 0; +} + /* nrn_threads_free() presumes all NrnThread and NrnThreadMembList data is * allocated with malloc(). This is not the case here, so let's try and fix * things up first. */ -void nrn_cleanup(bool clean_ion_global_map) { +void nrn_cleanup() { clear_event_queue(); // delete left-over TQItem gid2in.clear(); gid2out.clear(); @@ -1000,15 +1023,6 @@ void nrn_cleanup(bool clean_ion_global_map) { nrnthread_chkpnt = nullptr; } - // clean ions global maps - if (clean_ion_global_map) { - for (int i = 0; i < nrn_ion_global_map_size; i++) - free_memory(nrn_ion_global_map[i]); - free_memory(nrn_ion_global_map); - nrn_ion_global_map = nullptr; - nrn_ion_global_map_size = 0; - } - // clean NrnThreads for (int it = 0; it < nrn_nthread; ++it) { NrnThread* nt = nrn_threads + it; diff --git a/coreneuron/mechanism/mech/enginemech.cpp b/coreneuron/mechanism/mech/enginemech.cpp index 07a2bdb38..346f69cd7 100644 --- a/coreneuron/mechanism/mech/enginemech.cpp +++ b/coreneuron/mechanism/mech/enginemech.cpp @@ -28,6 +28,8 @@ void modl_reg() { extern bool nrn_have_gaps; extern bool nrn_use_fast_imem; +/// function defined in coreneuron library +extern void nrn_cleanup_ion_map(); } // namespace coreneuron /** Initialize mechanisms and run simulation using CoreNEURON @@ -37,7 +39,9 @@ extern bool nrn_use_fast_imem; int solve_core(int argc, char** argv) { mk_mech_init(argc, argv); coreneuron::modl_reg(); - return run_solve_core(argc, argv); + int ret = run_solve_core(argc, argv); + coreneuron::nrn_cleanup_ion_map(); + return ret; } extern "C" { diff --git a/coreneuron/nrniv/nrniv_decl.h b/coreneuron/nrniv/nrniv_decl.h index 705991aa4..a34bf0d06 100644 --- a/coreneuron/nrniv/nrniv_decl.h +++ b/coreneuron/nrniv/nrniv_decl.h @@ -67,7 +67,8 @@ extern double* stdindex2ptr(int mtype, int index, NrnThread&); extern void delete_trajectory_requests(NrnThread&); extern int nrn_setup_multiple; extern int nrn_setup_extracon; -extern void nrn_cleanup(bool clean_ion_global_map = true); +extern void nrn_cleanup(); +extern void nrn_cleanup_ion_map(); extern void BBS_netpar_solve(double); extern void nrn_mkPatternStim(const char* filename); extern int nrn_extra_thread0_vdata; diff --git a/tests/jenkins/neuron_direct.py b/tests/jenkins/neuron_direct.py index 8d12b7d4a..391a7ce9b 100644 --- a/tests/jenkins/neuron_direct.py +++ b/tests/jenkins/neuron_direct.py @@ -27,10 +27,12 @@ tvstd = tv.cl() i_memstd = i_mem.cl() -#h.CoreNeuronRun[0].run() pc = h.ParallelContext() h.stdinit() pc.nrncore_run("-e %g"%h.tstop, 0) +# running second time for testing multiple executions +h.stdinit() +pc.nrncore_run("-e %g"%h.tstop, 0) if not bool(tv.eq(tvstd)): print("Voltage times are different")