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:
parent
243d4a798b
commit
446f817111
@ -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) :
|
||||||
|
@ -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));
|
||||||
|
@ -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 {
|
||||||
|
@ -44,3 +44,7 @@ void pass_sgf(gf_view<imfreq,scalar_valued> g) {
|
|||||||
h5_write(file, "g", g);
|
h5_write(file, "g", g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
// 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::keyboard_interrupt const & e) {\
|
||||||
|
PyErr_SetString(PyExc_KeyboardInterrupt, e.what());\
|
||||||
|
return RET; }\
|
||||||
catch(triqs::exception const & e) {\
|
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());\
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
Loading…
Reference in New Issue
Block a user