2014-06-06 22:46:16 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <vector>
|
2014-06-06 23:23:24 +00:00
|
|
|
#include <utility>
|
2014-06-06 22:46:16 +00:00
|
|
|
#include <string>
|
2014-09-17 15:23:25 +00:00
|
|
|
#include <memory>
|
2014-06-06 22:46:16 +00:00
|
|
|
#include "util/thread.h"
|
2014-06-06 23:23:24 +00:00
|
|
|
#include "util/pair.h"
|
2014-06-06 22:46:16 +00:00
|
|
|
#include "util/script_state.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2014-09-17 15:23:25 +00:00
|
|
|
struct script_state_manager {
|
|
|
|
mutex g_code_mutex;
|
|
|
|
std::vector<pair<bool, std::string>> g_code;
|
|
|
|
mutex g_state_mutex;
|
|
|
|
std::vector<script_state> g_states;
|
|
|
|
std::vector<script_state> g_available_states;
|
|
|
|
};
|
|
|
|
|
|
|
|
static script_state_manager & get_manager() {
|
|
|
|
static script_state_manager g_manager;
|
|
|
|
return g_manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
static script_state_manager & g_aux = get_manager(); // force manager to be initialized at startup
|
2014-06-06 22:46:16 +00:00
|
|
|
|
|
|
|
/** \brief Execute \c code in all states in the pool */
|
|
|
|
void system_dostring(char const * code) {
|
2014-09-17 15:23:25 +00:00
|
|
|
script_state_manager & m = get_manager();
|
2014-06-06 22:46:16 +00:00
|
|
|
{
|
|
|
|
// Execute code in all existing states
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_state_mutex);
|
|
|
|
for (auto & s : m.g_states) {
|
2014-06-06 22:46:16 +00:00
|
|
|
s.dostring(code);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// Save code for future states
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_code_mutex);
|
|
|
|
m.g_code.push_back(mk_pair(true, code));
|
2014-06-06 23:23:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Import \c fname in all states in the pool */
|
|
|
|
void system_import(char const * fname) {
|
2014-09-17 15:23:25 +00:00
|
|
|
script_state_manager & m = get_manager();
|
2014-06-06 23:23:24 +00:00
|
|
|
{
|
|
|
|
// Import file in all existing states
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_state_mutex);
|
|
|
|
for (auto & s : m.g_states) {
|
2014-06-18 05:04:09 +00:00
|
|
|
s.import_explicit(fname);
|
2014-06-06 23:23:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// Save module for future states
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_code_mutex);
|
|
|
|
m.g_code.push_back(mk_pair(false, fname));
|
2014-06-06 22:46:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static script_state get_state() {
|
2014-09-17 15:23:25 +00:00
|
|
|
script_state_manager & m = get_manager();
|
2014-06-06 22:46:16 +00:00
|
|
|
{
|
|
|
|
// Try to reuse existing state
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_state_mutex);
|
|
|
|
if (!m.g_available_states.empty()) {
|
|
|
|
script_state r(m.g_available_states.back());
|
|
|
|
m.g_available_states.pop_back();
|
2014-06-06 22:46:16 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Execute existing code in new state
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_code_mutex);
|
2014-06-06 22:46:16 +00:00
|
|
|
script_state r;
|
2014-09-17 15:23:25 +00:00
|
|
|
for (auto const & p : m.g_code) {
|
2014-06-06 23:23:24 +00:00
|
|
|
if (p.first)
|
|
|
|
r.dostring(p.second.c_str());
|
|
|
|
else
|
2014-06-28 02:52:49 +00:00
|
|
|
r.import_explicit(p.second.c_str());
|
2014-06-06 23:23:24 +00:00
|
|
|
}
|
2014-06-06 22:46:16 +00:00
|
|
|
{
|
|
|
|
// save new state in vector of all states
|
2014-09-17 15:23:25 +00:00
|
|
|
lock_guard<mutex> lk(m.g_state_mutex);
|
|
|
|
m.g_states.push_back(r);
|
2014-06-06 22:46:16 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void recycle_state(script_state s) {
|
2014-09-17 15:23:25 +00:00
|
|
|
script_state_manager & m = get_manager();
|
|
|
|
lock_guard<mutex> lk(m.g_state_mutex);
|
|
|
|
m.g_available_states.push_back(s);
|
2014-06-06 22:46:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct script_state_ref {
|
|
|
|
script_state m_state;
|
|
|
|
script_state_ref():m_state(get_state()) {}
|
|
|
|
~script_state_ref() { recycle_state(m_state); }
|
|
|
|
};
|
|
|
|
|
2014-06-07 17:18:32 +00:00
|
|
|
// If reset == true, then reset/release the (script_state) thread local storage
|
|
|
|
// If reset == false, then return (script_state) thread local
|
|
|
|
static script_state * get_script_state_ref(bool reset) {
|
|
|
|
LEAN_THREAD_PTR(script_state_ref) g_thread_state;
|
|
|
|
if (reset) {
|
|
|
|
g_thread_state.reset(nullptr);
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
if (!g_thread_state.get())
|
|
|
|
g_thread_state.reset(new script_state_ref());
|
|
|
|
return &((*g_thread_state).m_state);
|
|
|
|
}
|
2014-06-06 22:46:16 +00:00
|
|
|
}
|
|
|
|
|
2014-06-07 17:18:32 +00:00
|
|
|
script_state get_thread_script_state() { return *get_script_state_ref(false); }
|
|
|
|
void release_thread_script_state() { get_script_state_ref(true); }
|
2014-06-06 22:46:16 +00:00
|
|
|
}
|