diff --git a/CMakeLists.txt b/CMakeLists.txt index 78d36ce..c270ce1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ SET (CMAKE_CXX_FLAGS_GDB " -Wall -ggdb") include_directories(include) -find_package(Boost 1.36.0) +find_package(Boost 1.36.0 COMPONENTS thread) if (Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) add_executable(chaiscript_eval src/main.cpp) diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 07d011b..d553e62 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -280,8 +280,12 @@ namespace chaiscript */ Object_Cache &get_object_cache() { - static Object_Cache oc; - return oc; + static boost::thread_specific_ptr oc; + if (!oc.get()) + { + oc.reset(new Object_Cache); + } + return *oc; } /** diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b0bc6ae..88c1ebb 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "boxed_value.hpp" #include "type_info.hpp" @@ -155,13 +156,14 @@ namespace chaiscript public: typedef std::map Type_Name_Map; typedef std::map Scope; - typedef boost::shared_ptr, std::deque > > Stack; + typedef std::pair, std::deque > StackData; + typedef boost::shared_ptr Stack; Dispatch_Engine() - : m_scopes(new Stack::element_type()), - m_place_holder(boost::shared_ptr(new Placeholder_Object())) + : m_place_holder(boost::shared_ptr(new Placeholder_Object())) { - m_scopes->second.push_back(Scope()); + StackData &stack = get_stack_data(); + stack.second.push_back(Scope()); } /** @@ -170,7 +172,9 @@ namespace chaiscript bool add(const Proxy_Function &f, const std::string &name) { validate_object_name(name); - m_scopes->first.erase(name); + + StackData &stack = get_stack_data(); + stack.first.erase(name); return add_function(f, name); } @@ -189,13 +193,15 @@ namespace chaiscript void add(const Boxed_Value &obj, const std::string &name) { validate_object_name(name); - for (int i = m_scopes->second.size()-1; i >= 0; --i) + StackData &stack = get_stack_data(); + + for (int i = stack.second.size()-1; i >= 0; --i) { - std::map::const_iterator itr = (m_scopes->second)[i].find(name); - if (itr != (m_scopes->second)[i].end()) + std::map::const_iterator itr = (stack.second)[i].find(name); + if (itr != (stack.second)[i].end()) { - m_scopes->first.erase(name); - (m_scopes->second)[i][name] = Boxed_Value(obj); + stack.first.erase(name); + (stack.second)[i][name] = Boxed_Value(obj); return; } } @@ -208,9 +214,10 @@ namespace chaiscript */ void add_object(const std::string &name, const Boxed_Value &obj) { - m_scopes->first.erase(name); + StackData &stack = get_stack_data(); validate_object_name(name); - m_scopes->second.back()[name] = Boxed_Value(obj); + stack.first.erase(name); + stack.second.back()[name] = Boxed_Value(obj); } /** @@ -218,7 +225,8 @@ namespace chaiscript */ void new_scope() { - m_scopes->second.push_back(Scope()); + StackData &stack = get_stack_data(); + stack.second.push_back(Scope()); } /** @@ -226,16 +234,17 @@ namespace chaiscript */ void pop_scope() { - if (m_scopes->second.size() > 1) + StackData &stack = get_stack_data(); + if (stack.second.size() > 1) { - Scope &scope(m_scopes->second.back()); + Scope &scope(stack.second.back()); for (Scope::const_iterator itr = scope.begin(); itr != scope.end(); ++itr) { - m_scopes->first.erase(itr->first); + stack.first.erase(itr->first); } - m_scopes->second.pop_back(); + stack.second.pop_back(); } else { throw std::range_error("Unable to pop global stack"); } @@ -246,7 +255,8 @@ namespace chaiscript */ Stack get_stack() { - return m_scopes; + setup_stack(); + return m_thread_stack->stack; } /** @@ -256,18 +266,25 @@ namespace chaiscript */ Stack set_stack(const Stack &s) { - Stack old = m_scopes; - m_scopes = s; + setup_stack(); + + Stack old = m_thread_stack->stack; + m_thread_stack->stack = s; return old; } - Stack new_stack() + Stack new_stack() const { Stack s(new Stack::element_type()); s->second.push_back(Scope()); return s; } + void sync_cache() + { + get_stack()->first.clear(); + } + /** * Searches the current stack for an object of the given name * includes a special overload for the _ place holder object to @@ -280,7 +297,8 @@ namespace chaiscript return m_place_holder; } - std::map &cache = m_scopes->first; + StackData &stack = get_stack_data(); + std::map &cache = stack.first; std::map::const_iterator itr = cache.find(name); if (itr != cache.end()) @@ -288,10 +306,10 @@ namespace chaiscript return itr->second; } - for (int i = m_scopes->second.size()-1; i >= 0; --i) + for (int i = stack.second.size()-1; i >= 0; --i) { - std::map::const_iterator itr = (m_scopes->second)[i].find(name); - if (itr != (m_scopes->second)[i].end()) + std::map::const_iterator itr = (stack.second)[i].find(name); + if (itr != (stack.second)[i].end()) { cache[name] = itr->second; return itr->second; @@ -315,6 +333,7 @@ namespace chaiscript */ void add(const Type_Info &ti, const std::string &name) { + boost::unique_lock l(m_mutex); m_types.insert(std::make_pair(name, ti)); } @@ -323,6 +342,7 @@ namespace chaiscript */ Type_Info get_type(const std::string &name) const { + boost::shared_lock l(m_mutex); Type_Name_Map::const_iterator itr = m_types.find(name); if (itr != m_types.end()) @@ -340,6 +360,7 @@ namespace chaiscript */ std::string get_type_name(const Type_Info &ti) const { + boost::shared_lock l(m_mutex); for (Type_Name_Map::const_iterator itr = m_types.begin(); itr != m_types.end(); ++itr) @@ -358,6 +379,7 @@ namespace chaiscript */ std::vector > get_types() const { + boost::shared_lock l(m_mutex); return std::vector >(m_types.begin(), m_types.end()); } @@ -367,6 +389,8 @@ namespace chaiscript std::vector::mapped_type> > get_function(const std::string &t_name) const { + boost::shared_lock l(m_mutex); + std::pair::const_iterator, std::multimap::const_iterator> range = m_functions.equal_range(t_name); @@ -378,6 +402,7 @@ namespace chaiscript */ bool function_exists(const std::string &name) const { + boost::shared_lock l(m_mutex); return m_functions.find(name) != m_functions.end(); } @@ -386,28 +411,52 @@ namespace chaiscript */ std::vector > get_functions() const { + boost::shared_lock l(m_mutex); return std::vector >(m_functions.begin(), m_functions.end()); } void add_reserved_word(const std::string &name) { + boost::unique_lock l(m_mutex); m_reserved_words.insert(name); } - Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) + Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { + boost::shared_lock l(m_mutex); std::pair::const_iterator, std::multimap::const_iterator> range = m_functions.equal_range(t_name); + l.unlock(); return dispatch(range.first, range.second, params); } private: + /** + * Returns the current stack + */ + StackData &get_stack_data() const + { + setup_stack(); + return *(m_thread_stack->stack); + } + + void setup_stack() const + { + if (!m_thread_stack.get()) + { + m_thread_stack.reset(new Stack_Holder(new_stack())); + } + + } + /** * Throw a reserved_word exception if the name is not allowed */ - void validate_object_name(const std::string &name) + void validate_object_name(const std::string &name) const { + boost::shared_lock l(m_mutex); + if (m_reserved_words.find(name) != m_reserved_words.end()) { throw reserved_word_error(name); @@ -421,6 +470,8 @@ namespace chaiscript */ bool add_function(const Proxy_Function &f, const std::string &t_name) { + boost::unique_lock l(m_mutex); + std::pair::const_iterator, std::multimap::const_iterator> range = m_functions.equal_range(t_name); @@ -437,11 +488,24 @@ namespace chaiscript return true; } - Stack m_scopes; + mutable boost::shared_mutex m_mutex; + + struct Stack_Holder + { + Stack_Holder(Stack s) + : stack(s) + { + } + + Stack stack; + }; + + mutable boost::thread_specific_ptr m_thread_stack; std::multimap m_functions; Type_Name_Map m_types; Boxed_Value m_place_holder; + std::set m_reserved_words; }; diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 5f7a1bb..60fe00e 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -21,25 +21,31 @@ namespace chaiscript Eval_Engine engine; std::set loaded_files; - - ChaiScript_Parser parser; + mutable boost::shared_mutex mutex; + mutable boost::recursive_mutex use_mutex; /** * Evaluates the given string in by parsing it and running the results through the evaluator */ Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__") { + ChaiScript_Parser parser; + + engine.sync_cache(); + //debug_print(tokens); Boxed_Value value; - parser.clear_match_stack(); // Keep a cache of all loaded filenames and use the char * from this cache to pass // to the parser. This is so that the parser does not have the overhead of passing // around and copying strings + // + boost::unique_lock l(mutex); loaded_files.insert(filename); try { if (parser.parse(input, loaded_files.find(filename)->c_str())) { + l.unlock(); //parser.show_match_stack(); value = eval_token(engine, parser.ast()); } @@ -60,8 +66,11 @@ namespace chaiscript void use(const std::string &filename) { + boost::lock_guard l(use_mutex); + boost::shared_lock l2(mutex); if (loaded_files.count(filename) == 0) { + l2.unlock(); eval_file(filename); } } diff --git a/src/multithreaded.cpp b/src/multithreaded.cpp new file mode 100644 index 0000000..9126ef9 --- /dev/null +++ b/src/multithreaded.cpp @@ -0,0 +1,35 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org) +// and Jason Turner (lefticus@gmail.com) +// http://www.chaiscript.com + +#include + +#include + +#include + + +void do_work(chaiscript::ChaiScript &c) +{ + c("use(\"work.chai\"); do_chai_work();"); +} + +int main(int argc, char *argv[]) { + std::string input; + chaiscript::ChaiScript chai; + + std::vector > threads; + + for (int i = 0; i < argc - 1; ++i) + { + threads.push_back(boost::shared_ptr(new boost::thread(boost::bind(do_work, boost::ref(chai))))); + } + + for (int i = 0; i < argc - 1; ++i) + { + threads[i]->join(); + } +} + diff --git a/src/work.chai b/src/work.chai new file mode 100644 index 0000000..c1afa47 --- /dev/null +++ b/src/work.chai @@ -0,0 +1,10 @@ +def do_chai_work() +{ + var i = 0; + for (var k = 0; k<100000; ++k) + { + i += k; + } + + print(i); +}