3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 05:43: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:
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).
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) :

View File

@ -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 !

View File

@ -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 {

View File

@ -44,3 +44,7 @@ void pass_sgf(gf_view<imfreq,scalar_valued> 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).
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")

View File

@ -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; }\

View File

@ -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

View File

@ -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

View File

@ -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(); }
}
}

View File

@ -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