mirror of
https://github.com/Z3Prover/z3
synced 2025-05-10 01:05:47 +00:00
Merge 78c5800a99
into 0e4c033e30
This commit is contained in:
commit
32e8697abd
4 changed files with 148 additions and 39 deletions
|
@ -18,28 +18,44 @@ Revision History:
|
||||||
--*/
|
--*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include "util/event_handler.h"
|
#include "util/event_handler.h"
|
||||||
|
#include "util/scoped_ctrl_c.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Generic event handler for invoking cancel method.
|
\brief Generic event handler for invoking cancel method.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class cancel_eh : public event_handler {
|
class cancel_eh : public event_handler {
|
||||||
bool m_canceled = false;
|
std::atomic<bool> m_canceled = false;
|
||||||
bool m_auto_cancel = false;
|
bool m_auto_cancel = false;
|
||||||
T & m_obj;
|
T & m_obj;
|
||||||
public:
|
public:
|
||||||
cancel_eh(T & o): m_obj(o) {}
|
cancel_eh(T & o): m_obj(o) {}
|
||||||
~cancel_eh() override { if (m_canceled) m_obj.dec_cancel(); if (m_auto_cancel) m_obj.auto_cancel(); }
|
~cancel_eh() override { if (m_canceled) m_obj.dec_cancel(); if (m_auto_cancel) m_obj.auto_cancel(); }
|
||||||
void operator()(event_handler_caller_t caller_id) override {
|
void operator()(event_handler_caller_t caller_id) override {
|
||||||
|
signal_lock();
|
||||||
if (!m_canceled) {
|
if (!m_canceled) {
|
||||||
m_caller_id = caller_id;
|
m_caller_id = caller_id;
|
||||||
m_canceled = true;
|
m_canceled = true;
|
||||||
m_obj.inc_cancel();
|
m_obj.inc_cancel();
|
||||||
}
|
}
|
||||||
|
signal_unlock();
|
||||||
|
}
|
||||||
|
bool canceled() {
|
||||||
|
bool ret;
|
||||||
|
if (!m_canceled)
|
||||||
|
return false;
|
||||||
|
signal_lock();
|
||||||
|
ret = m_canceled;
|
||||||
|
signal_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
signal_lock();
|
||||||
|
m_canceled = false;
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
bool canceled() const { return m_canceled; }
|
|
||||||
void reset() { m_canceled = false; }
|
|
||||||
T& t() { return m_obj; }
|
T& t() { return m_obj; }
|
||||||
void set_auto_cancel() { m_auto_cancel = true; }
|
void set_auto_cancel() { m_auto_cancel = true; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,16 +19,12 @@ Revision History:
|
||||||
#include "util/rlimit.h"
|
#include "util/rlimit.h"
|
||||||
#include "util/common_msgs.h"
|
#include "util/common_msgs.h"
|
||||||
#include "util/mutex.h"
|
#include "util/mutex.h"
|
||||||
|
#include "util/scoped_ctrl_c.h"
|
||||||
|
|
||||||
static DECLARE_MUTEX(g_rlimit_mux);
|
|
||||||
|
|
||||||
void initialize_rlimit() {
|
void initialize_rlimit() {
|
||||||
ALLOC_MUTEX(g_rlimit_mux);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalize_rlimit() {
|
void finalize_rlimit() {
|
||||||
DEALLOC_MUTEX(g_rlimit_mux);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reslimit::reslimit() {
|
reslimit::reslimit() {
|
||||||
|
@ -77,50 +73,57 @@ char const* reslimit::get_cancel_msg() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::push_child(reslimit* r) {
|
void reslimit::push_child(reslimit* r) {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
m_children.push_back(r);
|
m_children.push_back(r);
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::pop_child() {
|
void reslimit::pop_child() {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
m_count += m_children.back()->m_count;
|
m_count += m_children.back()->m_count;
|
||||||
m_children.back()->m_count = 0;
|
m_children.back()->m_count = 0;
|
||||||
m_children.pop_back();
|
m_children.pop_back();
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::pop_child(reslimit* r) {
|
void reslimit::pop_child(reslimit* r) {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
for (unsigned i = 0; i < m_children.size(); ++i) {
|
for (unsigned i = 0; i < m_children.size(); ++i) {
|
||||||
if (m_children[i] == r) {
|
if (m_children[i] == r) {
|
||||||
m_count += r->m_count;
|
m_count += r->m_count;
|
||||||
r->m_count = 0;
|
r->m_count = 0;
|
||||||
m_children.erase(m_children.begin() + i);
|
m_children.erase(m_children.begin() + i);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void reslimit::cancel() {
|
void reslimit::cancel() {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
set_cancel(m_cancel+1);
|
set_cancel(m_cancel+1);
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::reset_cancel() {
|
void reslimit::reset_cancel() {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
set_cancel(0);
|
set_cancel(0);
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::inc_cancel() {
|
void reslimit::inc_cancel() {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
set_cancel(m_cancel + 1);
|
set_cancel(m_cancel + 1);
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::dec_cancel() {
|
void reslimit::dec_cancel() {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
if (m_cancel > 0) {
|
if (m_cancel > 0) {
|
||||||
set_cancel(m_cancel-1);
|
set_cancel(m_cancel-1);
|
||||||
}
|
}
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::set_cancel(unsigned f) {
|
void reslimit::set_cancel(unsigned f) {
|
||||||
|
@ -151,8 +154,9 @@ void reslimit::push_timeout(unsigned ms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::inc_cancel(unsigned k) {
|
void reslimit::inc_cancel(unsigned k) {
|
||||||
lock_guard lock(*g_rlimit_mux);
|
signal_lock();
|
||||||
set_cancel(m_cancel + k);
|
set_cancel(m_cancel + k);
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reslimit::auto_cancel() {
|
void reslimit::auto_cancel() {
|
||||||
|
|
|
@ -12,28 +12,94 @@ Abstract:
|
||||||
Author:
|
Author:
|
||||||
|
|
||||||
Leonardo de Moura (leonardo) 2011-04-27.
|
Leonardo de Moura (leonardo) 2011-04-27.
|
||||||
|
Mikulas Patocka 2025-04-05. (rewritten to be thread safe)
|
||||||
|
|
||||||
Revision History:
|
Revision History:
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
#include<signal.h>
|
#include <signal.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <mutex>
|
||||||
#include "util/scoped_ctrl_c.h"
|
#include "util/scoped_ctrl_c.h"
|
||||||
#include "util/gparams.h"
|
#include "util/gparams.h"
|
||||||
|
|
||||||
static scoped_ctrl_c * g_obj = nullptr;
|
#ifdef _WINDOWS
|
||||||
|
#define USE_SIGNAL
|
||||||
|
#endif
|
||||||
|
|
||||||
static void on_ctrl_c(int) {
|
static std::recursive_mutex context_lock;
|
||||||
if (g_obj->m_first) {
|
static std::vector<scoped_ctrl_c *> active_contexts;
|
||||||
g_obj->m_cancel_eh(CTRL_C_EH_CALLER);
|
#ifdef USE_SIGNAL
|
||||||
if (g_obj->m_once) {
|
static void (*old_handler)(int);
|
||||||
g_obj->m_first = false;
|
#else
|
||||||
signal(SIGINT, on_ctrl_c); // re-install the handler
|
static sigset_t context_old_set;
|
||||||
}
|
static struct sigaction old_sigaction;
|
||||||
|
static unsigned signal_lock_depth = 0;
|
||||||
|
#endif
|
||||||
|
static bool signal_handled = false;
|
||||||
|
|
||||||
|
void signal_lock(void) {
|
||||||
|
#ifdef USE_SIGNAL
|
||||||
|
context_lock.lock();
|
||||||
|
#else
|
||||||
|
sigset_t set, old_set;
|
||||||
|
sigemptyset(&set);
|
||||||
|
sigaddset(&set, SIGINT);
|
||||||
|
if (sigprocmask(SIG_BLOCK, &set, &old_set))
|
||||||
|
abort();
|
||||||
|
context_lock.lock();
|
||||||
|
signal_lock_depth++;
|
||||||
|
if (signal_lock_depth == 1)
|
||||||
|
context_old_set = old_set;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void signal_unlock(void) {
|
||||||
|
#ifdef USE_SIGNAL
|
||||||
|
context_lock.unlock();
|
||||||
|
#else
|
||||||
|
bool restore;
|
||||||
|
sigset_t old_set = context_old_set;
|
||||||
|
signal_lock_depth--;
|
||||||
|
restore = !signal_lock_depth;
|
||||||
|
context_lock.unlock();
|
||||||
|
if (restore) {
|
||||||
|
if (sigprocmask(SIG_SETMASK, &old_set, NULL))
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
else {
|
#endif
|
||||||
signal(SIGINT, g_obj->m_old_handler);
|
}
|
||||||
raise(SIGINT);
|
|
||||||
|
static void test_and_unhandle(void) {
|
||||||
|
if (!signal_handled)
|
||||||
|
return;
|
||||||
|
for (auto a : active_contexts) {
|
||||||
|
if (a->m_first)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef USE_SIGNAL
|
||||||
|
signal(SIGINT, old_handler);
|
||||||
|
#else
|
||||||
|
if (sigaction(SIGINT, &old_sigaction, NULL))
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
signal_handled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_sigint(int) {
|
||||||
|
signal_lock();
|
||||||
|
#ifdef USE_SIGNAL
|
||||||
|
if (signal_handled)
|
||||||
|
signal(SIGINT, on_sigint);
|
||||||
|
#endif
|
||||||
|
for (auto a : active_contexts) {
|
||||||
|
if (a->m_first)
|
||||||
|
a->m_cancel_eh(CTRL_C_EH_CALLER);
|
||||||
|
if (a->m_once)
|
||||||
|
a->m_first = false;
|
||||||
|
}
|
||||||
|
test_and_unhandle();
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ctrl_c::scoped_ctrl_c(event_handler & eh, bool once, bool enabled):
|
scoped_ctrl_c::scoped_ctrl_c(event_handler & eh, bool once, bool enabled):
|
||||||
|
@ -45,16 +111,38 @@ scoped_ctrl_c::scoped_ctrl_c(event_handler & eh, bool once, bool enabled):
|
||||||
if (gparams::get_value("ctrl_c") == "false")
|
if (gparams::get_value("ctrl_c") == "false")
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
g_obj = this;
|
signal_lock();
|
||||||
m_old_handler = signal(SIGINT, on_ctrl_c);
|
active_contexts.push_back(this);
|
||||||
|
if (!signal_handled) {
|
||||||
|
#ifdef USE_SIGNAL
|
||||||
|
old_handler = signal(SIGINT, on_sigint);
|
||||||
|
#else
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
|
sa.sa_handler = on_sigint;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
if (sigaction(SIGINT, &sa, &old_sigaction))
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
signal_handled = true;
|
||||||
|
}
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ctrl_c::~scoped_ctrl_c() {
|
scoped_ctrl_c::~scoped_ctrl_c() {
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
g_obj = m_old_scoped_ctrl_c;
|
signal_lock();
|
||||||
if (m_old_handler != SIG_ERR) {
|
for (auto it = active_contexts.begin(); it != active_contexts.end(); it++) {
|
||||||
signal(SIGINT, m_old_handler);
|
if (*it == this) {
|
||||||
|
active_contexts.erase(it);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
abort();
|
||||||
|
found:
|
||||||
|
test_and_unhandle();
|
||||||
|
signal_unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,14 @@ Revision History:
|
||||||
#include "util/event_handler.h"
|
#include "util/event_handler.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
|
void signal_lock(void);
|
||||||
|
void signal_unlock(void);
|
||||||
|
|
||||||
struct scoped_ctrl_c {
|
struct scoped_ctrl_c {
|
||||||
event_handler & m_cancel_eh;
|
event_handler & m_cancel_eh;
|
||||||
bool m_first;
|
bool m_first;
|
||||||
bool m_once;
|
bool m_once;
|
||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
void (STD_CALL *m_old_handler)(int);
|
|
||||||
scoped_ctrl_c * m_old_scoped_ctrl_c;
|
|
||||||
public:
|
public:
|
||||||
// If once == true, then the cancel_eh is invoked only at the first Ctrl-C.
|
// If once == true, then the cancel_eh is invoked only at the first Ctrl-C.
|
||||||
// The next time, the old signal handler will take over.
|
// The next time, the old signal handler will take over.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue