3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 22:03:43 +01:00

wrapper: add release_GIL_and_enable_signal option.

- Add to the wrapper generator (add_method) the release_GIL_and_enable_signal option which :

   - release the GIL
   - save the python signal handler
   - enable the C++ triqs signal handler instead.
   - undo all of this after the code runs, or in a case of exception.
   - used python include, ceval.h, line 72 comments and below.

- reworked the triqs::signal_handler.
  simple C like function, no object (no need).
  start, stop, received, cf header file.

- clean the call_back.cpp : only place using the signal directly
  (qmc uses the callback).
  in particular, remove the old BOOST CHRONO, since
  the std::chrono works fine on platforms we use now.
This commit is contained in:
Olivier Parcollet 2014-05-26 09:34:22 +02:00
parent 243d4a798b
commit 446f817111
10 changed files with 102 additions and 97 deletions

View File

@ -42,8 +42,16 @@ class cfunction :
auto result = self_c.method_name(a,b,c). auto result = self_c.method_name(a,b,c).
INCOMPATIBLE with c_name. INCOMPATIBLE with c_name.
If c_name is given, the default calling_pattern is made. If c_name is given, the default calling_pattern is made.
- release_GIL_and_enable_signal [expert only] :
For long functions in pure C++.
If true the GIL is released in the call of the C++ function and restored after the call.
It also saves the signal handler of python and restore it after the call,
and enable the C++ triqs signal_handler.
This allows e.g. to intercept Ctrl-C during the long C++ function.
The requirement is that the function wrapped must be pure C++, i.e.
no call whatsoever to the python C API, directly or indirectly.
""" """
def __init__(self, doc = '', is_method = False, no_self_c = False, is_static = False, **kw) : def __init__(self, doc = '', is_method = False, no_self_c = False, is_static = False, release_GIL_and_enable_signal = False, **kw) :
""" Use keywords to build, from the data. Cf doc of class""" """ Use keywords to build, from the data. Cf doc of class"""
self.c_name = kw.pop("c_name", None) self.c_name = kw.pop("c_name", None)
self._calling_pattern = kw.pop("calling_pattern", None) self._calling_pattern = kw.pop("calling_pattern", None)
@ -54,6 +62,7 @@ class cfunction :
self.doc = doc self.doc = doc
self.is_method = is_method self.is_method = is_method
self.is_static = is_static self.is_static = is_static
self.release_GIL_and_enable_signal = release_GIL_and_enable_signal
self.args = [] self.args = []
if 'signature' in kw : if 'signature' in kw :
assert 'rtype' not in kw and 'args' not in kw, "signature and rtype/args are not compatible" assert 'rtype' not in kw and 'args' not in kw, "signature and rtype/args are not compatible"
@ -511,7 +520,6 @@ class module_ :
the wrapped_type list the wrapped_type list
""" """
f = None f = None
print "argv", sys.argv
for path in module_path_list : for path in module_path_list :
hppfile = path + '/' + modulename + '.hpp' hppfile = path + '/' + modulename + '.hpp'
if os.path.exists(hppfile) : if os.path.exists(hppfile) :

View File

@ -16,6 +16,7 @@ using ${ns};
%endfor %endfor
#include <triqs/python_tools/wrapper_tools.hpp> #include <triqs/python_tools/wrapper_tools.hpp>
#include <triqs/utility/signal_handler.hpp>
using namespace triqs::py_tools; using namespace triqs::py_tools;
//--------------------- a dict of python function used in the module but not exposed to user (cf init function) ---------------- //--------------------- a dict of python function used in the module but not exposed to user (cf init function) ----------------
@ -547,7 +548,26 @@ template<typename T>
using self_class = ${self_c_type}; using self_class = ${self_c_type};
%endif %endif
try { try {
%if overload.release_GIL_and_enable_signal :
PyOS_sighandler_t sig = PyOS_getsig(SIGINT);
triqs::signal_handler::start(); // start the C++ signal handler
Py_BEGIN_ALLOW_THREADS;
try {
%endif
${overload.calling_pattern()}; // the call is here. It sets up "result" : sets up in the python layer. ${overload.calling_pattern()}; // the call is here. It sets up "result" : sets up in the python layer.
%if overload.release_GIL_and_enable_signal :
}
catch(...) {
// an error has occurred : clean GIL, handler and rethrow
Py_BLOCK_THREADS; // cf python include, ceval.h, line 72 comments and below.
triqs::signal_handler::stop(); // stop the C++ signal handler
PyOS_setsig(SIGINT, sig);
throw; //
}
Py_END_ALLOW_THREADS;
triqs::signal_handler::stop();
PyOS_setsig(SIGINT, sig);
%endif
%if not overload.is_constructor : %if not overload.is_constructor :
%if overload.rtype != "void" : %if overload.rtype != "void" :
py_result = convert_to_python(std::move(result)); py_result = convert_to_python(std::move(result));
@ -572,7 +592,7 @@ template<typename T>
} }
%endif %endif
} // end overload ${overload.c_signature()} } // end overload ${overload.c_signature()}
% endfor # overload %endfor # overload
%if has_overloads : %if has_overloads :
// finally, no overload was successful. Composing a detailed error message, with the reason of failure of all overload ! // finally, no overload was successful. Composing a detailed error message, with the reason of failure of all overload !

View File

@ -4,7 +4,7 @@
#include <ostream> #include <ostream>
#include <triqs/arrays.hpp> #include <triqs/arrays.hpp>
//#include <triqs/h5.hpp> //#include <triqs/h5.hpp>
#include <triqs/utility/signal_handler.hpp>
namespace triqs { namespace py_tools { namespace triqs { namespace py_tools {
class reductor; class reductor;
class reconstructor; class reconstructor;
@ -44,21 +44,13 @@ struct A {
void long_fnt() { void long_fnt() {
PyOS_sighandler_t sig = PyOS_getsig(SIGINT);
Py_BEGIN_ALLOW_THREADS;
for (int u = 0; u < 101; u +=10) { for (int u = 0; u < 101; u +=10) {
sleep(1); sleep(1);
if (!triqs::signal_handler().empty()) goto _end; if (triqs::signal_handler::received(true)) TRIQS_KEYBOARD_INTERRUPT;
count = u; count = u;
std::cout << " inner count " << count << std::endl; std::cout << " inner count " << count << std::endl;
} }
std::cout << " completed" << std::endl; std::cout << " completed" << std::endl;
_end:
Py_END_ALLOW_THREADS;
PyOS_setsig(SIGINT, sig);
// PyErr_SetString(PyExc_KeyboardInterrupt, " ended long_fnt");
} }
double m1(int u) const { double m1(int u) const {

View File

@ -44,3 +44,7 @@ void pass_sgf(gf_view<imfreq,scalar_valued> g) {
h5_write(file, "g", g); h5_write(file, "g", g);
} }
} }

View File

@ -39,6 +39,9 @@ g.add_method(py_name = "sm", c_name = "sm", signature = "int (int u)", is_static
# older syntax, giving rtype and args (better for automatic scripts). # older syntax, giving rtype and args (better for automatic scripts).
g.add_method(py_name = "m1f", c_name = "m1", rtype = "double", doc = "DOC of mm", args = [("int","u"), ("double","y",3)]) g.add_method(py_name = "m1f", c_name = "m1", rtype = "double", doc = "DOC of mm", args = [("int","u"), ("double","y",3)])
g.add_method(py_name = "long_fnt", c_name = "long_fnt", signature = "void()", release_GIL_and_enable_signal = True)
g.add_member(c_name = "count", c_type = "int",read_only=True)
# add the call operator # add the call operator
g.add_call(signature = "int(int u)", doc = "call op") g.add_call(signature = "int(int u)", doc = "call op")

View File

@ -11,7 +11,10 @@
// I can use the trace in triqs::exception // I can use the trace in triqs::exception
#define CATCH_AND_RETURN(MESS,RET)\ #define CATCH_AND_RETURN(MESS,RET)\
catch(triqs::exception const & e) {\ catch(triqs::keyboard_interrupt const & e) {\
PyErr_SetString(PyExc_KeyboardInterrupt, e.what());\
return RET; }\
catch(triqs::exception const & e) {\
auto err = std::string("Error " MESS "\nC++ error was : \n") + e.what();\ auto err = std::string("Error " MESS "\nC++ error was : \n") + e.what();\
PyErr_SetString(PyExc_RuntimeError, err.c_str());\ PyErr_SetString(PyExc_RuntimeError, err.c_str());\
return RET; }\ return RET; }\

View File

@ -18,50 +18,21 @@
* TRIQS. If not, see <http://www.gnu.org/licenses/>. * TRIQS. If not, see <http://www.gnu.org/licenses/>.
* *
******************************************************************************/ ******************************************************************************/
#include "callbacks.hpp" #include "callbacks.hpp"
#include "signal_handler.hpp" #include "signal_handler.hpp"
// switch to std. Remove old boost code when ok on several compilers
#ifndef TRIQS_USE_BOOST_CHRONO
#include <chrono> #include <chrono>
namespace triqs { namespace triqs {
namespace utility { namespace utility {
std::function<bool()> clock_callback(int time_in_seconds) { std::function<bool()> clock_callback(int time_in_seconds) {
signal_handler::start();
if (time_in_seconds <= 0) if (time_in_seconds <= 0)
return []() { return (!triqs::signal_handler().empty()); }; return []() { return (!triqs::signal_handler::received()); };
// auto end_time = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(time_in_seconds);
// return [end_time]() { return (!triqs::signal_handler().empty()) || boost::posix_time::second_clock::local_time() > end_time
auto end_time = std::chrono::system_clock::now() + std::chrono::seconds(time_in_seconds); auto end_time = std::chrono::system_clock::now() + std::chrono::seconds(time_in_seconds);
return [end_time]() { return (!triqs::signal_handler().empty()) || (std::chrono::system_clock::now() > end_time); }; return [end_time]() { return (!triqs::signal_handler::received()) || (std::chrono::system_clock::now() > end_time); };
} }
} }
} }
#else
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
namespace triqs {
namespace utility {
bool clock_callback_impl(boost::posix_time::ptime const& end_time) {
return (!triqs::signal_handler().empty()) || boost::posix_time::second_clock::local_time() > end_time;
}
bool false_callback_impl() { return (!triqs::signal_handler().empty()); }
std::function<bool()> clock_callback(int time_in_seconds) {
return (time_in_seconds > 0 ? boost::bind(&clock_callback_impl, boost::posix_time::second_clock::local_time() +
boost::posix_time::seconds(time_in_seconds))
: std::function<bool()>(&false_callback_impl));
}
}
}
#endif

View File

@ -47,10 +47,17 @@ namespace triqs {
template<typename T> runtime_error & operator <<( T && x) { exception::operator<<(x); return *this; } template<typename T> runtime_error & operator <<( T && x) { exception::operator<<(x); return *this; }
}; };
class keyboard_interrupt : public exception {
public:
keyboard_interrupt() throw() : exception() {}
virtual ~keyboard_interrupt() throw() {}
template<typename T> keyboard_interrupt & operator <<( T && x) { exception::operator<<(x); return *this; }
};
} }
#define TRIQS_ERROR(CLASS,NAME) throw CLASS()<<" Triqs "<<NAME<<" at "<<__FILE__<< " : "<<__LINE__<<"\n\n" #define TRIQS_ERROR(CLASS,NAME) throw CLASS()<<" Triqs "<<NAME<<" at "<<__FILE__<< " : "<<__LINE__<<"\n\n"
#define TRIQS_RUNTIME_ERROR TRIQS_ERROR(triqs::runtime_error,"runtime error") #define TRIQS_RUNTIME_ERROR TRIQS_ERROR(triqs::runtime_error,"runtime error")
#define TRIQS_KEYBOARD_INTERRUPT TRIQS_ERROR(triqs::keyboard_interrupt,"Ctrl-C")
#endif #endif

View File

@ -1,9 +1,8 @@
/******************************************************************************* /*******************************************************************************
* *
* TRIQS: a Toolbox for Research in Interacting Quantum Systems * TRIQS: a Toolbox for Research in Interacting Quantum Systems
* *
* Copyright (C) 2011 by M. Ferrero, O. Parcollet * Copyright (C) 2014 by O. Parcollet
* *
* TRIQS is free software: you can redistribute it and/or modify it under the * TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software * terms of the GNU General Public License as published by the Free Software
@ -19,38 +18,30 @@
* TRIQS. If not, see <http://www.gnu.org/licenses/>. * TRIQS. If not, see <http://www.gnu.org/licenses/>.
* *
******************************************************************************/ ******************************************************************************/
#include "signal_handler.hpp" #include "signal_handler.hpp"
//#include <time.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
//#include <stdlib.h> #include <vector>
//#include <unistd.h> #include <iostream>
// volatile sig_atomic_t signal_handler::keep_going;
namespace triqs { namespace triqs {
namespace signal_handler {
/* namespace {
namespace signal_details {
// The signal handler just clears the flag and re-enables itself. std::vector<int> signals_list;
// to replace with settimer if needed bool initialized = false;
void catch_alarm (int sig)
{ void slot(int signal) {
MySignalHandler::keep_going = 0; std::cerr << "TRIQS : Received signal " << signal << std::endl;
signal (sig, Catch_alarm); signals_list.push_back(signal);
} }
} }
*/
std::vector<int> signal_handler::signals_list;
signal_handler::signal_handler() { void start() {
static bool initialized;
if (initialized) return; if (initialized) return;
//keep_going = 1; /* Establish a handler for SIGALRM signals. */
static struct sigaction action; static struct sigaction action;
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
action.sa_handler = &signal_handler::slot; action.sa_handler = slot;
sigaction(SIGINT, &action, NULL); sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL); sigaction(SIGTERM, &action, NULL);
sigaction(SIGXCPU, &action, NULL); sigaction(SIGXCPU, &action, NULL);
@ -58,15 +49,23 @@ namespace triqs {
sigaction(SIGUSR1, &action, NULL); sigaction(SIGUSR1, &action, NULL);
sigaction(SIGUSR2, &action, NULL); sigaction(SIGUSR2, &action, NULL);
sigaction(SIGSTOP, &action, NULL); sigaction(SIGSTOP, &action, NULL);
//signal (SIGALRM, _MYSIGNAL::Catch_alarm);
//alarm (0);
initialized = true; initialized = true;
} }
void signal_handler::slot(int signal) { void stop() {
std::cerr << "Received signal " << signal << std::endl; signals_list.clear();
signals_list.push_back(signal); initialized = false;
} }
bool received(bool pop_) {
if (!initialized) start();
bool r = signals_list.size() != 0;
if (r && pop_) pop();
return r;
}
int last() { return signals_list.back(); }
void pop() { return signals_list.pop_back(); }
}
} }

View File

@ -3,7 +3,7 @@
* *
* TRIQS: a Toolbox for Research in Interacting Quantum Systems * TRIQS: a Toolbox for Research in Interacting Quantum Systems
* *
* Copyright (C) 2011 by M. Ferrero, O. Parcollet * Copyright (C) 2014 by O. Parcollet
* *
* TRIQS is free software: you can redistribute it and/or modify it under the * TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software * terms of the GNU General Public License as published by the Free Software
@ -19,25 +19,23 @@
* TRIQS. If not, see <http://www.gnu.org/licenses/>. * TRIQS. If not, see <http://www.gnu.org/licenses/>.
* *
******************************************************************************/ ******************************************************************************/
#pragma once
#ifndef TRIQS_SIGNAL_HANDLER_H
#define TRIQS_SIGNAL_HANDLER_H
#include <iostream>
#include <assert.h>
#include <vector>
namespace triqs { namespace triqs {
namespace signal_handler {
class signal_handler { /// Start the signal handler
static std::vector<int> signals_list; void start();
//static volatile sig_atomic_t keep_going;
public: /// Stop it. ?
signal_handler(); void stop();
bool empty(){ return (signals_list.size() ==0); }
int top(){ return signals_list.back(); } /// A signal has been received. If pop, and there is a signal, pop it.
void pop(){ return signals_list.pop_back(); } bool received(bool pop = false);
static void slot(int signal);
}; /// Last received.
int last();
/// pop the last signal
void pop();
}
} }
#endif