mirror of
https://github.com/Z3Prover/z3
synced 2025-04-11 03:33:35 +00:00
Merge ac03cc0529
into 8d81a2dcaf
This commit is contained in:
commit
4eb042aebc
|
@ -157,6 +157,7 @@ void context_params::updt_params(params_ref const & p) {
|
|||
void context_params::collect_param_descrs(param_descrs & d) {
|
||||
insert_rlimit(d);
|
||||
insert_timeout(d);
|
||||
insert_ctrl_c(d);
|
||||
d.insert("well_sorted_check", CPK_BOOL, "type checker", "false");
|
||||
d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
|
||||
d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
|
||||
|
|
|
@ -18,6 +18,7 @@ Revision History:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "util/event_handler.h"
|
||||
|
||||
/**
|
||||
|
@ -25,16 +26,15 @@ Revision History:
|
|||
*/
|
||||
template<typename T>
|
||||
class cancel_eh : public event_handler {
|
||||
bool m_canceled = false;
|
||||
std::atomic<bool> m_canceled = false;
|
||||
bool m_auto_cancel = false;
|
||||
T & m_obj;
|
||||
public:
|
||||
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(); }
|
||||
void operator()(event_handler_caller_t caller_id) override {
|
||||
if (!m_canceled) {
|
||||
if (!m_canceled.exchange(true)) {
|
||||
m_caller_id = caller_id;
|
||||
m_canceled = true;
|
||||
m_obj.inc_cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,46 +12,99 @@ Abstract:
|
|||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-04-27.
|
||||
Mikulas Patocka 2025-04-03. (rewritten to be thread safe)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<signal.h>
|
||||
#include <signal.h>
|
||||
#include <cstring>
|
||||
#include "util/gparams.h"
|
||||
#include "util/scoped_ctrl_c.h"
|
||||
|
||||
static scoped_ctrl_c * g_obj = nullptr;
|
||||
static std::mutex context_lock;
|
||||
static std::vector<scoped_ctrl_c *> active_contexts;
|
||||
static sigset_t context_old_set;
|
||||
static struct sigaction old_sigaction;
|
||||
static bool signal_handled = false;
|
||||
|
||||
static void on_ctrl_c(int) {
|
||||
if (g_obj->m_first) {
|
||||
g_obj->m_cancel_eh(CTRL_C_EH_CALLER);
|
||||
if (g_obj->m_once) {
|
||||
g_obj->m_first = false;
|
||||
signal(SIGINT, on_ctrl_c); // re-install the handler
|
||||
}
|
||||
static void signal_lock(void) {
|
||||
sigset_t set, old_set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGINT);
|
||||
if (sigprocmask(SIG_BLOCK, &set, &old_set))
|
||||
abort();
|
||||
context_lock.lock();
|
||||
context_old_set = old_set;
|
||||
}
|
||||
|
||||
static void signal_unlock(void) {
|
||||
sigset_t old_set = context_old_set;
|
||||
context_lock.unlock();
|
||||
if (sigprocmask(SIG_SETMASK, &old_set, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
static void test_and_unhandle(void) {
|
||||
if (!signal_handled)
|
||||
return;
|
||||
for (auto a : active_contexts) {
|
||||
if (a->m_first)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
signal(SIGINT, g_obj->m_old_handler);
|
||||
raise(SIGINT);
|
||||
if (sigaction(SIGINT, &old_sigaction, NULL))
|
||||
abort();
|
||||
signal_handled = false;
|
||||
}
|
||||
|
||||
static void on_sigint(int) {
|
||||
signal_lock();
|
||||
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):
|
||||
m_cancel_eh(eh),
|
||||
m_cancel_eh(eh),
|
||||
m_first(true),
|
||||
m_once(once),
|
||||
m_enabled(enabled),
|
||||
m_old_scoped_ctrl_c(g_obj) {
|
||||
m_enabled(enabled) {
|
||||
if (gparams::get_value("ctrl_c") == "false")
|
||||
m_enabled = false;
|
||||
if (m_enabled) {
|
||||
g_obj = this;
|
||||
m_old_handler = signal(SIGINT, on_ctrl_c);
|
||||
signal_lock();
|
||||
active_contexts.push_back(this);
|
||||
if (!signal_handled) {
|
||||
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();
|
||||
signal_handled = true;
|
||||
}
|
||||
signal_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
scoped_ctrl_c::~scoped_ctrl_c() {
|
||||
scoped_ctrl_c::~scoped_ctrl_c() {
|
||||
if (m_enabled) {
|
||||
g_obj = m_old_scoped_ctrl_c;
|
||||
if (m_old_handler != SIG_ERR) {
|
||||
signal(SIGINT, m_old_handler);
|
||||
signal_lock();
|
||||
for (auto it = active_contexts.begin(); it != active_contexts.end(); it++) {
|
||||
if (*it == this) {
|
||||
active_contexts.erase(it);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
abort();
|
||||
found:
|
||||
test_and_unhandle();
|
||||
signal_unlock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ struct scoped_ctrl_c {
|
|||
bool m_first;
|
||||
bool m_once;
|
||||
bool m_enabled;
|
||||
void (STD_CALL *m_old_handler)(int);
|
||||
scoped_ctrl_c * m_old_scoped_ctrl_c;
|
||||
public:
|
||||
// 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.
|
||||
|
|
Loading…
Reference in a new issue