mirror of
https://github.com/triqs/dft_tools
synced 2024-12-25 13:53:40 +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).
|
||||
INCOMPATIBLE with c_name.
|
||||
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"""
|
||||
self.c_name = kw.pop("c_name", None)
|
||||
self._calling_pattern = kw.pop("calling_pattern", None)
|
||||
@ -54,6 +62,7 @@ class cfunction :
|
||||
self.doc = doc
|
||||
self.is_method = is_method
|
||||
self.is_static = is_static
|
||||
self.release_GIL_and_enable_signal = release_GIL_and_enable_signal
|
||||
self.args = []
|
||||
if 'signature' in kw :
|
||||
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
|
||||
"""
|
||||
f = None
|
||||
print "argv", sys.argv
|
||||
for path in module_path_list :
|
||||
hppfile = path + '/' + modulename + '.hpp'
|
||||
if os.path.exists(hppfile) :
|
||||
|
@ -16,6 +16,7 @@ using ${ns};
|
||||
%endfor
|
||||
|
||||
#include <triqs/python_tools/wrapper_tools.hpp>
|
||||
#include <triqs/utility/signal_handler.hpp>
|
||||
using namespace triqs::py_tools;
|
||||
|
||||
//--------------------- 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};
|
||||
%endif
|
||||
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.
|
||||
%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 overload.rtype != "void" :
|
||||
py_result = convert_to_python(std::move(result));
|
||||
@ -572,7 +592,7 @@ template<typename T>
|
||||
}
|
||||
%endif
|
||||
} // end overload ${overload.c_signature()}
|
||||
% endfor # overload
|
||||
%endfor # overload
|
||||
|
||||
%if has_overloads :
|
||||
// finally, no overload was successful. Composing a detailed error message, with the reason of failure of all overload !
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <ostream>
|
||||
#include <triqs/arrays.hpp>
|
||||
//#include <triqs/h5.hpp>
|
||||
|
||||
#include <triqs/utility/signal_handler.hpp>
|
||||
namespace triqs { namespace py_tools {
|
||||
class reductor;
|
||||
class reconstructor;
|
||||
@ -39,26 +39,18 @@ struct A {
|
||||
}
|
||||
|
||||
static int sm(int i) { return i*2;}
|
||||
|
||||
|
||||
int count =0;
|
||||
|
||||
void long_fnt() {
|
||||
|
||||
PyOS_sighandler_t sig = PyOS_getsig(SIGINT);
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
for (int u = 0; u < 101; u +=10) {
|
||||
sleep(1);
|
||||
if (!triqs::signal_handler().empty()) goto _end;
|
||||
if (triqs::signal_handler::received(true)) TRIQS_KEYBOARD_INTERRUPT;
|
||||
count = u;
|
||||
std::cout << " inner count " << count << 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 {
|
||||
|
@ -44,3 +44,7 @@ void pass_sgf(gf_view<imfreq,scalar_valued> 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).
|
||||
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
|
||||
g.add_call(signature = "int(int u)", doc = "call op")
|
||||
|
||||
|
@ -11,7 +11,10 @@
|
||||
|
||||
// I can use the trace in triqs::exception
|
||||
#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();\
|
||||
PyErr_SetString(PyExc_RuntimeError, err.c_str());\
|
||||
return RET; }\
|
||||
|
@ -18,50 +18,21 @@
|
||||
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "callbacks.hpp"
|
||||
#include "signal_handler.hpp"
|
||||
|
||||
// switch to std. Remove old boost code when ok on several compilers
|
||||
#ifndef TRIQS_USE_BOOST_CHRONO
|
||||
#include <chrono>
|
||||
|
||||
namespace triqs {
|
||||
namespace utility {
|
||||
|
||||
std::function<bool()> clock_callback(int time_in_seconds) {
|
||||
signal_handler::start();
|
||||
if (time_in_seconds <= 0)
|
||||
return []() { return (!triqs::signal_handler().empty()); };
|
||||
|
||||
// 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
|
||||
return []() { return (!triqs::signal_handler::received()); };
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
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_RUNTIME_ERROR TRIQS_ERROR(triqs::runtime_error,"runtime error")
|
||||
#define TRIQS_KEYBOARD_INTERRUPT TRIQS_ERROR(triqs::keyboard_interrupt,"Ctrl-C")
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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
|
||||
* 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/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "signal_handler.hpp"
|
||||
//#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <unistd.h>
|
||||
// volatile sig_atomic_t signal_handler::keep_going;
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
namespace triqs {
|
||||
namespace signal_handler {
|
||||
|
||||
/*
|
||||
namespace signal_details {
|
||||
// The signal handler just clears the flag and re-enables itself.
|
||||
// to replace with settimer if needed
|
||||
void catch_alarm (int sig)
|
||||
{
|
||||
MySignalHandler::keep_going = 0;
|
||||
signal (sig, Catch_alarm);
|
||||
}
|
||||
}
|
||||
*/
|
||||
std::vector<int> signal_handler::signals_list;
|
||||
namespace {
|
||||
|
||||
signal_handler::signal_handler() {
|
||||
static bool initialized;
|
||||
if (initialized) return;
|
||||
//keep_going = 1; /* Establish a handler for SIGALRM signals. */
|
||||
std::vector<int> signals_list;
|
||||
bool initialized = false;
|
||||
|
||||
void slot(int signal) {
|
||||
std::cerr << "TRIQS : Received signal " << signal << std::endl;
|
||||
signals_list.push_back(signal);
|
||||
}
|
||||
}
|
||||
|
||||
void start() {
|
||||
if (initialized) return;
|
||||
static struct sigaction action;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = &signal_handler::slot;
|
||||
action.sa_handler = slot;
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGXCPU, &action, NULL);
|
||||
@ -58,15 +49,23 @@ namespace triqs {
|
||||
sigaction(SIGUSR1, &action, NULL);
|
||||
sigaction(SIGUSR2, &action, NULL);
|
||||
sigaction(SIGSTOP, &action, NULL);
|
||||
//signal (SIGALRM, _MYSIGNAL::Catch_alarm);
|
||||
//alarm (0);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void signal_handler::slot(int signal) {
|
||||
std::cerr << "Received signal " << signal << std::endl;
|
||||
signals_list.push_back(signal);
|
||||
void stop() {
|
||||
signals_list.clear();
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
#pragma once
|
||||
namespace triqs {
|
||||
namespace signal_handler {
|
||||
|
||||
#ifndef TRIQS_SIGNAL_HANDLER_H
|
||||
#define TRIQS_SIGNAL_HANDLER_H
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
/// Start the signal handler
|
||||
void start();
|
||||
|
||||
namespace triqs {
|
||||
/// Stop it. ?
|
||||
void stop();
|
||||
|
||||
/// A signal has been received. If pop, and there is a signal, pop it.
|
||||
bool received(bool pop = false);
|
||||
|
||||
class signal_handler {
|
||||
static std::vector<int> signals_list;
|
||||
//static volatile sig_atomic_t keep_going;
|
||||
public:
|
||||
signal_handler();
|
||||
bool empty(){ return (signals_list.size() ==0); }
|
||||
int top(){ return signals_list.back(); }
|
||||
void pop(){ return signals_list.pop_back(); }
|
||||
static void slot(int signal);
|
||||
};
|
||||
/// Last received.
|
||||
int last();
|
||||
|
||||
/// pop the last signal
|
||||
void pop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user