diff --git a/bindings/python/libs/client/__init__.py b/bindings/python/libs/client/__init__.py index 10c6646fbfe..675761239d8 100644 --- a/bindings/python/libs/client/__init__.py +++ b/bindings/python/libs/client/__init__.py @@ -4,3 +4,5 @@ from .file import File as File from .url import URL as URL from .copyprocess import CopyProcess as CopyProcess + +import XRootD.client.finalize diff --git a/bindings/python/libs/client/finalize.py b/bindings/python/libs/client/finalize.py new file mode 100644 index 00000000000..1be36245166 --- /dev/null +++ b/bindings/python/libs/client/finalize.py @@ -0,0 +1,35 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2012-2014 by European Organization for Nuclear Research (CERN) +# Author: Michal Simon +#------------------------------------------------------------------------------- +# This file is part of the XRootD software suite. +# +# XRootD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# XRootD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with XRootD. If not, see . +# +# In applying this licence, CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +#------------------------------------------------------------------------------ + +import atexit +from pyxrootd import client + +@atexit.register +def finalize(): + """Python atexit handler, will stop all XRootD client threads + (XrdCl JobManager, TaskManager and Poller) in order to ensure + no Python APIs are called after the Python Interpreter gets + finalized. + """ + client.__XrdCl_Stop_Threads() diff --git a/bindings/python/src/PyXRootDFinalize.hh b/bindings/python/src/PyXRootDFinalize.hh new file mode 100644 index 00000000000..6adb0d0738d --- /dev/null +++ b/bindings/python/src/PyXRootDFinalize.hh @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2012-2013 by European Organization for Nuclear Research (CERN) +// Author: Michal Simon +//------------------------------------------------------------------------------ +// This file is part of the XRootD software suite. +// +// XRootD is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// XRootD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with XRootD. If not, see . +// +// In applying this licence, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +//------------------------------------------------------------------------------ +#ifndef BINDINGS_PYTHON_SRC_PYXROOTDFINALIZE_HH_ +#define BINDINGS_PYTHON_SRC_PYXROOTDFINALIZE_HH_ + +#include "PyXRootD.hh" + +#include "XrdCl/XrdClDefaultEnv.hh" +#include "XrdCl/XrdClPostMaster.hh" + +namespace PyXRootD +{ + + //---------------------------------------------------------------------------- + //! Waits until XrdCl JobManager, TaskManager and Poller will stop gracefully. + //! + //! To be used in Python native atexit handler in order to make sure there are + //! no outstanding threads after the Python interpreter got finalized. + //---------------------------------------------------------------------------- + PyObject* __XrdCl_Stop_Threads( PyObject *self, PyObject* ) + { + Py_BEGIN_ALLOW_THREADS + XrdCl::DefaultEnv::GetPostMaster()->Stop(); + Py_END_ALLOW_THREADS + Py_RETURN_NONE; + } +} + +#endif /* BINDINGS_PYTHON_SRC_PYXROOTDFINALIZE_HH_ */ diff --git a/bindings/python/src/PyXRootDModule.cc b/bindings/python/src/PyXRootDModule.cc index 52626792f8d..8792c1a35fa 100644 --- a/bindings/python/src/PyXRootDModule.cc +++ b/bindings/python/src/PyXRootDModule.cc @@ -27,6 +27,7 @@ #include "PyXRootDFile.hh" #include "PyXRootDCopyProcess.hh" #include "PyXRootDURL.hh" +#include "PyXRootDFinalize.hh" namespace PyXRootD { @@ -40,7 +41,9 @@ namespace PyXRootD //---------------------------------------------------------------------------- static PyMethodDef module_methods[] = { - { NULL } /* Sentinel */ + // The finalization routine used in atexit handler. + { "__XrdCl_Stop_Threads", __XrdCl_Stop_Threads, METH_NOARGS, "Stop XrdCl threads." }, + { NULL, NULL, 0, NULL } }; #if PY_MAJOR_VERSION >= 3