Add support for (soft) interrupts
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
272089044e
commit
63e596885c
6 changed files with 185 additions and 2 deletions
|
@ -28,6 +28,7 @@ endif ()
|
|||
|
||||
# GMP
|
||||
include(cmake/FindGMP.cmake)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} ${GMP_LIBRARIES})
|
||||
|
||||
# tcmalloc
|
||||
include(cmake/FindTcmalloc.cmake)
|
||||
|
@ -40,10 +41,13 @@ include_directories(${LEAN_SOURCE_DIR}/numerics)
|
|||
include_directories(${LEAN_SOURCE_DIR}/interval)
|
||||
|
||||
add_subdirectory(util)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} util)
|
||||
add_subdirectory(numerics)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} numerics)
|
||||
add_subdirectory(interval)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} util numerics interval ${GMP_LIBRARIES})
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} interval)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
|
||||
add_subdirectory(shell)
|
||||
add_subdirectory(tests/util)
|
||||
add_subdirectory(tests/numerics)
|
||||
add_subdirectory(tests/interval)
|
||||
|
|
3
src/tests/util/CMakeLists.txt
Normal file
3
src/tests/util/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
add_executable(interrupt interrupt.cpp)
|
||||
target_link_libraries(interrupt ${EXTRA_LIBS})
|
||||
add_test(interrupt ${CMAKE_CURRENT_BINARY_DIR}/interrupt)
|
45
src/tests/util/interrupt.cpp
Normal file
45
src/tests/util/interrupt.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include "interrupt.h"
|
||||
#include "test.h"
|
||||
|
||||
std::mutex g_stdout_mutex;
|
||||
|
||||
static void loop(unsigned i) {
|
||||
try {
|
||||
while (true) {
|
||||
lean::check_interrupt();
|
||||
}
|
||||
}
|
||||
catch (lean::interrupt) {
|
||||
std::lock_guard<std::mutex> lock(g_stdout_mutex);
|
||||
std::cout << "interrupted " << i << ".\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void tst1() {
|
||||
lean::interruptible_thread t1([](){ loop(1); });
|
||||
lean::interruptible_thread t2([](){ loop(2); });
|
||||
|
||||
std::chrono::milliseconds dura(200);
|
||||
std::this_thread::sleep_for(dura);
|
||||
t2.request_interrupt();
|
||||
|
||||
std::this_thread::sleep_for(dura);
|
||||
t1.request_interrupt();
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
int main() {
|
||||
tst1();
|
||||
return 0;
|
||||
}
|
|
@ -1 +1 @@
|
|||
add_library(util trace.cpp debug.cpp name.cpp exception.cpp verbosity.cpp)
|
||||
add_library(util trace.cpp debug.cpp name.cpp exception.cpp verbosity.cpp interrupt.cpp)
|
||||
|
|
57
src/util/interrupt.cpp
Normal file
57
src/util/interrupt.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "interrupt.h"
|
||||
|
||||
namespace lean {
|
||||
|
||||
thread_local std::atomic_bool g_interrupt;
|
||||
|
||||
void request_interrupt() {
|
||||
g_interrupt.store(true);
|
||||
}
|
||||
|
||||
void reset_interrupt() {
|
||||
g_interrupt.store(false);
|
||||
}
|
||||
|
||||
bool interrupted() {
|
||||
return g_interrupt.load();
|
||||
}
|
||||
|
||||
void check_interrupt() {
|
||||
if (interrupted())
|
||||
throw interrupt();
|
||||
}
|
||||
|
||||
std::atomic_bool * interruptible_thread::get_flag_addr() {
|
||||
return &g_interrupt;
|
||||
}
|
||||
|
||||
bool interruptible_thread::interrupted() const {
|
||||
std::atomic_bool * f = m_flag_addr.load();
|
||||
if (f == nullptr)
|
||||
return false;
|
||||
return f->load();
|
||||
}
|
||||
|
||||
bool interruptible_thread::request_interrupt() {
|
||||
std::atomic_bool * f = m_flag_addr.load();
|
||||
if (f == nullptr)
|
||||
return false;
|
||||
f->store(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void interruptible_thread::join() {
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
bool interruptible_thread::joinable() {
|
||||
return m_thread.joinable();
|
||||
}
|
||||
|
||||
}
|
74
src/util/interrupt.h
Normal file
74
src/util/interrupt.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
// APIs for interrupting Lean.
|
||||
|
||||
namespace lean {
|
||||
|
||||
/**
|
||||
\brief Mark flag for interrupting current thread.
|
||||
*/
|
||||
void request_interrupt();
|
||||
/**
|
||||
\brief Reset (interrupt) flag for current thread.
|
||||
*/
|
||||
void reset_interrupt();
|
||||
|
||||
/**
|
||||
\brief Return true if the
|
||||
*/
|
||||
bool interrupted();
|
||||
|
||||
class interrupt : public std::exception {
|
||||
public:
|
||||
virtual char const * what() const noexcept { return "interrupted"; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Throw an interrupt exception if the (interrupt) flag is set.
|
||||
*/
|
||||
void check_interrupt();
|
||||
|
||||
/**
|
||||
\brief Thread that provides a method for setting its interrupt flag.
|
||||
*/
|
||||
class interruptible_thread {
|
||||
private:
|
||||
std::atomic<std::atomic_bool*> m_flag_addr;
|
||||
std::thread m_thread;
|
||||
static std::atomic_bool * get_flag_addr();
|
||||
public:
|
||||
template<typename Function, typename... Args>
|
||||
interruptible_thread(Function && fun, Args &&... args):
|
||||
m_flag_addr(nullptr),
|
||||
m_thread(
|
||||
[&](Function&& fun, Args&&... args) {
|
||||
m_flag_addr.store(get_flag_addr());
|
||||
fun(std::forward<Args>(args)...);
|
||||
},
|
||||
std::forward<Function>(fun),
|
||||
std::forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
/**
|
||||
\brief Return true iff an interrupt request has been made to the current thread.
|
||||
*/
|
||||
bool interrupted() const;
|
||||
/**
|
||||
\brief Send a interrupt request to the current thread. Return
|
||||
true iff the request has been successfully performed.
|
||||
*/
|
||||
bool request_interrupt();
|
||||
|
||||
void join();
|
||||
bool joinable();
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue