Browse Source

Add support for lua_newthread in the script engine. An environment that is sandboxed

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
62ef8125c9

+ 3 - 2
programs/FinalComposite.ankiprog

@@ -86,9 +86,10 @@ void main()
 	out_color += blueNoise / 255.0;
 	out_color += blueNoise / 255.0;
 #endif
 #endif
 
 
-#if 0
+#if 1
 	{
 	{
-		out_color = vec3(textureLod(u_isRt, uv, 0.0).rgb);
+		//out_color = vec3(textureLod(u_isRt, uv, 0.0).rgb);
+		out_color -= vec3(0.25);
 	}
 	}
 #endif
 #endif
 
 

+ 1 - 0
src/anki/Script.h

@@ -6,3 +6,4 @@
 #pragma once
 #pragma once
 
 
 #include <anki/script/ScriptManager.h>
 #include <anki/script/ScriptManager.h>
+#include <anki/script/ScriptEnvironment.h>

+ 13 - 1
src/anki/script/Common.h

@@ -5,14 +5,26 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <anki/Config.h>
+#include <anki/util/Allocator.h>
+#include <anki/util/Ptr.h>
 
 
 namespace anki
 namespace anki
 {
 {
 
 
+// Forward
+class LuaBinder;
+class ScriptManager;
+
+class ScriptObject;
+class ScriptEnvironment;
+
 #define ANKI_SCRIPT_LOGI(...) ANKI_LOG("SCRI", NORMAL, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGI(...) ANKI_LOG("SCRI", NORMAL, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGE(...) ANKI_LOG("SCRI", ERROR, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGE(...) ANKI_LOG("SCRI", ERROR, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGW(...) ANKI_LOG("SCRI", WARNING, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGW(...) ANKI_LOG("SCRI", WARNING, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGF(...) ANKI_LOG("SCRI", FATAL, __VA_ARGS__)
 #define ANKI_SCRIPT_LOGF(...) ANKI_LOG("SCRI", FATAL, __VA_ARGS__)
 
 
+using ScriptAllocator = HeapAllocator<U8>;
+
+using ScriptEnvironmentPtr = IntrusivePtr<ScriptEnvironment>;
+
 } // end namespace anki
 } // end namespace anki

+ 135 - 0
src/anki/script/Logger.cpp

@@ -0,0 +1,135 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// WARNING: This file is auto generated.
+
+#include <anki/script/LuaBinder.h>
+
+namespace anki
+{
+
+/// Pre-wrap function logi.
+static inline int pwraplogi(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	LuaBinder::checkArgsCount(l, 1);
+
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 1, arg0))
+	{
+		return -1;
+	}
+
+	// Call the function
+	ANKI_SCRIPT_LOGI(arg0);
+
+	return 0;
+}
+
+/// Wrap function logi.
+static int wraplogi(lua_State* l)
+{
+	int res = pwraplogi(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap function loge.
+static inline int pwraploge(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	LuaBinder::checkArgsCount(l, 1);
+
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 1, arg0))
+	{
+		return -1;
+	}
+
+	// Call the function
+	ANKI_SCRIPT_LOGE(arg0);
+
+	return 0;
+}
+
+/// Wrap function loge.
+static int wraploge(lua_State* l)
+{
+	int res = pwraploge(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap function logw.
+static inline int pwraplogw(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	LuaBinder::checkArgsCount(l, 1);
+
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 1, arg0))
+	{
+		return -1;
+	}
+
+	// Call the function
+	ANKI_SCRIPT_LOGW(arg0);
+
+	return 0;
+}
+
+/// Wrap function logw.
+static int wraplogw(lua_State* l)
+{
+	int res = pwraplogw(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Wrap the module.
+void wrapModuleLogger(lua_State* l)
+{
+	LuaBinder::pushLuaCFunc(l, "logi", wraplogi);
+	LuaBinder::pushLuaCFunc(l, "loge", wraploge);
+	LuaBinder::pushLuaCFunc(l, "logw", wraplogw);
+}
+
+} // end namespace anki

+ 34 - 0
src/anki/script/Logger.xml

@@ -0,0 +1,34 @@
+<glue>
+	<head><![CDATA[// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// WARNING: This file is auto generated.
+
+#include <anki/script/LuaBinder.h>
+
+namespace anki {]]></head>
+	<functions>
+		<function name="logi">
+			<overrideCall>ANKI_SCRIPT_LOGI(arg0);</overrideCall>
+			<args>
+				<arg>const char*</arg>
+			</args>
+		</function>
+		<function name="loge">
+			<overrideCall>ANKI_SCRIPT_LOGE(arg0);</overrideCall>
+			<args>
+				<arg>const char*</arg>
+			</args>
+		</function>
+		<function name="logw">
+			<overrideCall>ANKI_SCRIPT_LOGW(arg0);</overrideCall>
+			<args>
+				<arg>const char*</arg>
+			</args>
+		</function>
+	</functions>
+	<tail><![CDATA[} // end namespace anki]]></tail>
+</glue>
+

+ 28 - 7
src/anki/script/LuaBinder.cpp

@@ -27,7 +27,7 @@ LuaBinder::~LuaBinder()
 	ANKI_ASSERT(m_alloc.getMemoryPool().getAllocationsCount() == 0 && "Leaking memory");
 	ANKI_ASSERT(m_alloc.getMemoryPool().getAllocationsCount() == 0 && "Leaking memory");
 }
 }
 
 
-Error LuaBinder::create(Allocator<U8>& alloc, void* parent)
+Error LuaBinder::create(ScriptAllocator alloc, void* parent)
 {
 {
 	m_parent = parent;
 	m_parent = parent;
 	m_alloc = alloc;
 	m_alloc = alloc;
@@ -90,21 +90,20 @@ void* LuaBinder::luaAllocCallback(void* userData, void* ptr, PtrSize osize, PtrS
 	return out;
 	return out;
 }
 }
 
 
-Error LuaBinder::evalString(const CString& str)
+Error LuaBinder::evalString(lua_State* state, const CString& str)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(LUA_EXEC);
 	ANKI_TRACE_SCOPED_EVENT(LUA_EXEC);
 
 
 	Error err = Error::NONE;
 	Error err = Error::NONE;
-	int e = luaL_dostring(m_l, &str[0]);
+	int e = luaL_dostring(state, &str[0]);
 	if(e)
 	if(e)
 	{
 	{
-		ANKI_SCRIPT_LOGE("%s (line:%d)", lua_tostring(m_l, -1));
-		lua_pop(m_l, 1);
+		ANKI_SCRIPT_LOGE("%s (line:%d)", lua_tostring(state, -1));
+		lua_pop(state, 1);
 		err = Error::USER_DATA;
 		err = Error::USER_DATA;
 	}
 	}
 
 
-	lua_gc(m_l, LUA_GCCOLLECT, 0);
-
+	garbageCollect(state);
 	return err;
 	return err;
 }
 }
 
 
@@ -240,4 +239,26 @@ void LuaBinder::luaFree(lua_State* l, void* ptr)
 	binder->m_alloc.getMemoryPool().free(ptr);
 	binder->m_alloc.getMemoryPool().free(ptr);
 }
 }
 
 
+LuaThread LuaBinder::newLuaThread()
+{
+	LuaThread out;
+
+	out.m_luaState = lua_newthread(m_l);
+	out.m_reference = luaL_ref(m_l, LUA_REGISTRYINDEX);
+
+	return out;
+}
+
+void LuaBinder::destroyLuaThread(LuaThread& luaThread)
+{
+	if(luaThread.m_luaState)
+	{
+		// Unref it, garbage collector will take care of it
+		luaL_unref(m_l, LUA_REGISTRYINDEX, luaThread.m_reference);
+	}
+
+	luaThread.m_luaState = nullptr;
+	luaThread.m_reference = -1;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 73 - 33
src/anki/script/LuaBinder.h

@@ -19,6 +19,9 @@
 namespace anki
 namespace anki
 {
 {
 
 
+/// @addtogroup script
+/// @{
+
 /// LUA userdata.
 /// LUA userdata.
 class LuaUserData
 class LuaUserData
 {
 {
@@ -89,24 +92,56 @@ private:
 	U64 m_addressOrGarbageCollect = 0; ///< Encodes an address or a flag if it's for garbage collection.
 	U64 m_addressOrGarbageCollect = 0; ///< Encodes an address or a flag if it's for garbage collection.
 };
 };
 
 
-/// Lua binder class. A wrapper on top of LUA
-class LuaBinder
+/// An instance of the original lua state with its own state.
+class LuaThread : public NonCopyable
 {
 {
+	friend class LuaBinder;
+
 public:
 public:
-	template<typename T>
-	using Allocator = ChainAllocator<T>;
+	lua_State* m_luaState = nullptr;
+
+	LuaThread() = default;
+
+	LuaThread(LuaThread&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~LuaThread()
+	{
+		ANKI_ASSERT(m_luaState == nullptr && "Forgot to deleteLuaThread");
+	}
+
+	LuaThread& operator=(LuaThread&& b)
+	{
+		ANKI_ASSERT(m_luaState == nullptr);
+		m_luaState = b.m_luaState;
+		b.m_luaState = nullptr;
+
+		m_reference = b.m_reference;
+		b.m_reference = -1;
+		return *this;
+	}
 
 
+private:
+	int m_reference = -1;
+};
+
+/// Lua binder class. A wrapper on top of LUA
+class LuaBinder : public NonCopyable
+{
+public:
 	LuaBinder();
 	LuaBinder();
 	~LuaBinder();
 	~LuaBinder();
 
 
-	ANKI_USE_RESULT Error create(Allocator<U8>& alloc, void* parent);
+	ANKI_USE_RESULT Error create(ScriptAllocator alloc, void* parent);
 
 
 	lua_State* getLuaState()
 	lua_State* getLuaState()
 	{
 	{
 		return m_l;
 		return m_l;
 	}
 	}
 
 
-	Allocator<U8> getAllocator() const
+	ScriptAllocator getAllocator() const
 	{
 	{
 		return m_alloc;
 		return m_alloc;
 	}
 	}
@@ -118,10 +153,28 @@ public:
 
 
 	/// Expose a variable to the lua state
 	/// Expose a variable to the lua state
 	template<typename T>
 	template<typename T>
-	void exposeVariable(const char* name, T* y);
+	static void exposeVariable(lua_State* state, CString name, T* y)
+	{
+		void* ptr = lua_newuserdata(state, sizeof(LuaUserData));
+		LuaUserData* ud = static_cast<LuaUserData*>(ptr);
+		ud->initPointed(getWrappedTypeSignature<T>(), y);
+		luaL_setmetatable(state, getWrappedTypeName<T>());
+		lua_setglobal(state, name.cstr());
+	}
 
 
 	/// Evaluate a string
 	/// Evaluate a string
-	ANKI_USE_RESULT Error evalString(const CString& str);
+	static Error evalString(lua_State* state, const CString& str);
+
+	static void garbageCollect(lua_State* state)
+	{
+		lua_gc(state, LUA_GCCOLLECT, 0);
+	}
+
+	/// New LuaThread.
+	LuaThread newLuaThread();
+
+	/// Destroy a LuaThread.
+	void destroyLuaThread(LuaThread& luaThread);
 
 
 	/// For debugging purposes
 	/// For debugging purposes
 	static void stackDump(lua_State* l);
 	static void stackDump(lua_State* l);
@@ -143,7 +196,16 @@ public:
 
 
 	/// Get a number from the stack.
 	/// Get a number from the stack.
 	template<typename TNumber>
 	template<typename TNumber>
-	static ANKI_USE_RESULT Error checkNumber(lua_State* l, I stackIdx, TNumber& number);
+	static ANKI_USE_RESULT Error checkNumber(lua_State* l, I stackIdx, TNumber& number)
+	{
+		lua_Number lnum;
+		Error err = checkNumberInternal(l, stackIdx, lnum);
+		if(!err)
+		{
+			number = lnum;
+		}
+		return err;
+	}
 
 
 	/// Get a string from the stack.
 	/// Get a string from the stack.
 	static ANKI_USE_RESULT Error checkString(lua_State* l, I32 stackIdx, const char*& out);
 	static ANKI_USE_RESULT Error checkString(lua_State* l, I32 stackIdx, const char*& out);
@@ -167,7 +229,7 @@ public:
 	static const char* getWrappedTypeName();
 	static const char* getWrappedTypeName();
 
 
 private:
 private:
-	Allocator<U8> m_alloc;
+	ScriptAllocator m_alloc;
 	lua_State* m_l = nullptr;
 	lua_State* m_l = nullptr;
 	void* m_parent = nullptr; ///< Point to the ScriptManager
 	void* m_parent = nullptr; ///< Point to the ScriptManager
 
 
@@ -175,28 +237,6 @@ private:
 
 
 	static ANKI_USE_RESULT Error checkNumberInternal(lua_State* l, I32 stackIdx, lua_Number& number);
 	static ANKI_USE_RESULT Error checkNumberInternal(lua_State* l, I32 stackIdx, lua_Number& number);
 };
 };
-
-template<typename TNumber>
-inline Error LuaBinder::checkNumber(lua_State* l, I stackIdx, TNumber& number)
-{
-	lua_Number lnum;
-	Error err = checkNumberInternal(l, stackIdx, lnum);
-	if(!err)
-	{
-		number = lnum;
-	}
-
-	return err;
-}
-
-template<typename T>
-inline void LuaBinder::exposeVariable(const char* name, T* y)
-{
-	void* ptr = lua_newuserdata(m_l, sizeof(LuaUserData));
-	LuaUserData* ud = static_cast<LuaUserData*>(ptr);
-	ud->initPointed(getWrappedTypeSignature<T>(), y);
-	luaL_setmetatable(m_l, getWrappedTypeName<T>());
-	lua_setglobal(m_l, name);
-}
+/// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 23 - 0
src/anki/script/ScriptEnvironment.cpp

@@ -0,0 +1,23 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/script/ScriptEnvironment.h>
+#include <anki/script/ScriptManager.h>
+
+namespace anki
+{
+
+ScriptEnvironment::~ScriptEnvironment()
+{
+	m_manager->destroyLuaThread(m_thread);
+}
+
+Error ScriptEnvironment::init()
+{
+	m_thread = m_manager->newLuaThread();
+	return Error::NONE;
+}
+
+} // end namespace anki

+ 48 - 0
src/anki/script/ScriptEnvironment.h

@@ -0,0 +1,48 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/script/ScriptObject.h>
+#include <anki/script/LuaBinder.h>
+
+namespace anki
+{
+
+/// @addtogroup script
+/// @{
+
+/// A sandboxed LUA environment.
+class ScriptEnvironment : public ScriptObject
+{
+public:
+	ScriptEnvironment(ScriptManager* manager)
+		: ScriptObject(manager)
+	{
+	}
+
+	~ScriptEnvironment();
+
+	Error init();
+
+	/// Expose a variable to the scripting engine.
+	template<typename T>
+	void exposeVariable(const char* name, T* y)
+	{
+		LuaBinder::exposeVariable<T>(m_thread.m_luaState, name, y);
+	}
+
+	/// Evaluate a string
+	ANKI_USE_RESULT Error evalString(const CString& str)
+	{
+		return LuaBinder::evalString(m_thread.m_luaState, str);
+	}
+
+private:
+	LuaThread m_thread;
+};
+/// @}
+
+} // end namespace anki

+ 10 - 1
src/anki/script/ScriptManager.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #include <anki/script/ScriptManager.h>
 #include <anki/script/ScriptManager.h>
+#include <anki/script/ScriptEnvironment.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Logger.h>
 
 
 namespace anki
 namespace anki
@@ -11,6 +12,7 @@ namespace anki
 
 
 // Forward
 // Forward
 #define ANKI_SCRIPT_CALL_WRAP(x_) void wrapModule##x_(lua_State*)
 #define ANKI_SCRIPT_CALL_WRAP(x_) void wrapModule##x_(lua_State*)
+ANKI_SCRIPT_CALL_WRAP(Logger);
 ANKI_SCRIPT_CALL_WRAP(Math);
 ANKI_SCRIPT_CALL_WRAP(Math);
 ANKI_SCRIPT_CALL_WRAP(Renderer);
 ANKI_SCRIPT_CALL_WRAP(Renderer);
 ANKI_SCRIPT_CALL_WRAP(Scene);
 ANKI_SCRIPT_CALL_WRAP(Scene);
@@ -32,7 +34,7 @@ Error ScriptManager::init(AllocAlignedCallback allocCb, void* allocCbData, Scene
 
 
 	m_scene = scene;
 	m_scene = scene;
 	m_r = renderer;
 	m_r = renderer;
-	m_alloc = ChainAllocator<U8>(allocCb, allocCbData, 1024, 1.0, 0);
+	m_alloc = ScriptAllocator(allocCb, allocCbData);
 
 
 	ANKI_CHECK(m_lua.create(m_alloc, this));
 	ANKI_CHECK(m_lua.create(m_alloc, this));
 
 
@@ -40,6 +42,7 @@ Error ScriptManager::init(AllocAlignedCallback allocCb, void* allocCbData, Scene
 	lua_State* l = m_lua.getLuaState();
 	lua_State* l = m_lua.getLuaState();
 
 
 #define ANKI_SCRIPT_CALL_WRAP(x_) wrapModule##x_(l)
 #define ANKI_SCRIPT_CALL_WRAP(x_) wrapModule##x_(l)
+	ANKI_SCRIPT_CALL_WRAP(Logger);
 	ANKI_SCRIPT_CALL_WRAP(Math);
 	ANKI_SCRIPT_CALL_WRAP(Math);
 	ANKI_SCRIPT_CALL_WRAP(Renderer);
 	ANKI_SCRIPT_CALL_WRAP(Renderer);
 	ANKI_SCRIPT_CALL_WRAP(Scene);
 	ANKI_SCRIPT_CALL_WRAP(Scene);
@@ -49,4 +52,10 @@ Error ScriptManager::init(AllocAlignedCallback allocCb, void* allocCbData, Scene
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
+Error ScriptManager::newScriptEnvironment(ScriptEnvironmentPtr& out)
+{
+	out.reset(m_alloc.newInstance<ScriptEnvironment>(this));
+	return out->init();
+}
+
 } // end namespace anki
 } // end namespace anki

+ 38 - 12
src/anki/script/ScriptManager.h

@@ -17,31 +17,35 @@ class MainRenderer;
 /// @addtogroup script
 /// @addtogroup script
 /// @{
 /// @{
 
 
-/// The scripting manager
+/// The scripting manager.
 class ScriptManager
 class ScriptManager
 {
 {
 public:
 public:
+	ScriptManager();
+	~ScriptManager();
+
+	/// Create the script manager.
+	ANKI_USE_RESULT Error init(
+		AllocAlignedCallback allocCb, void* allocCbData, SceneGraph* scene, MainRenderer* renderer);
+
 	/// Expose a variable to the scripting engine.
 	/// Expose a variable to the scripting engine.
 	template<typename T>
 	template<typename T>
 	void exposeVariable(const char* name, T* y)
 	void exposeVariable(const char* name, T* y)
 	{
 	{
-		m_lua.exposeVariable<T>(name, y);
+		LockGuard<Mutex> lock(n_luaMtx);
+		LuaBinder::exposeVariable<T>(m_lua.getLuaState(), name, y);
 	}
 	}
 
 
 	/// Evaluate a string
 	/// Evaluate a string
 	ANKI_USE_RESULT Error evalString(const CString& str)
 	ANKI_USE_RESULT Error evalString(const CString& str)
 	{
 	{
-		return m_lua.evalString(str);
+		LockGuard<Mutex> lock(n_luaMtx);
+		return LuaBinder::evalString(m_lua.getLuaState(), str);
 	}
 	}
 
 
-anki_internal:
-	ScriptManager();
-	~ScriptManager();
-
-	/// Create the script manager.
-	ANKI_USE_RESULT Error init(
-		AllocAlignedCallback allocCb, void* allocCbData, SceneGraph* scene, MainRenderer* renderer);
+	ANKI_USE_RESULT Error newScriptEnvironment(ScriptEnvironmentPtr& out);
 
 
+anki_internal:
 	SceneGraph& getSceneGraph()
 	SceneGraph& getSceneGraph()
 	{
 	{
 		return *m_scene;
 		return *m_scene;
@@ -52,13 +56,35 @@ anki_internal:
 		return *m_r;
 		return *m_r;
 	}
 	}
 
 
+	LuaBinder& getLuaBinder()
+	{
+		return m_lua;
+	}
+
+	ScriptAllocator getAllocator() const
+	{
+		return m_alloc;
+	}
+
+	LuaThread newLuaThread()
+	{
+		LockGuard<Mutex> lock(n_luaMtx);
+		return m_lua.newLuaThread();
+	}
+
+	void destroyLuaThread(LuaThread& thread)
+	{
+		LockGuard<Mutex> lock(n_luaMtx);
+		m_lua.destroyLuaThread(thread);
+	}
+
 private:
 private:
 	SceneGraph* m_scene = nullptr;
 	SceneGraph* m_scene = nullptr;
 	MainRenderer* m_r = nullptr;
 	MainRenderer* m_r = nullptr;
-	ChainAllocator<U8> m_alloc;
+	ScriptAllocator m_alloc;
 	LuaBinder m_lua;
 	LuaBinder m_lua;
+	Mutex n_luaMtx;
 };
 };
-
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 17 - 0
src/anki/script/ScriptObject.cpp

@@ -0,0 +1,17 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/script/ScriptObject.h>
+#include <anki/script/ScriptManager.h>
+
+namespace anki
+{
+
+ScriptAllocator ScriptObject::getAllocator() const
+{
+	return m_manager->getAllocator();
+}
+
+} // end namespace anki

+ 45 - 0
src/anki/script/ScriptObject.h

@@ -0,0 +1,45 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/script/Common.h>
+
+namespace anki
+{
+
+/// @addtogroup script
+/// @{
+
+/// The base of all script objects.
+class ScriptObject
+{
+public:
+	ScriptObject(ScriptManager* manager)
+		: m_manager(manager)
+	{
+		ANKI_ASSERT(manager);
+	}
+
+	virtual ~ScriptObject()
+	{
+	}
+
+	ScriptAllocator getAllocator() const;
+
+	Atomic<I32>& getRefcount()
+	{
+		return m_refcount;
+	}
+
+protected:
+	ScriptManager* m_manager;
+
+private:
+	Atomic<I32> m_refcount = {0};
+};
+/// @}
+
+} // end namespace anki

+ 30 - 3
tests/script/LuaBinder.cpp

@@ -3,9 +3,9 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#include "tests/framework/Framework.h"
-#include "anki/script/ScriptManager.h"
-#include "anki/Math.h"
+#include <tests/framework/Framework.h>
+#include <anki/Script.h>
+#include <anki/Math.h>
 
 
 static const char* script = R"(
 static const char* script = R"(
 b = Vec4.new(0, 0, 0, 1.1)
 b = Vec4.new(0, 0, 0, 1.1)
@@ -38,3 +38,30 @@ ANKI_TEST(Script, LuaBinder)
 	ANKI_TEST_EXPECT_EQ(v4, Vec4(6, 12, 0, 5.5));
 	ANKI_TEST_EXPECT_EQ(v4, Vec4(6, 12, 0, 5.5));
 	ANKI_TEST_EXPECT_EQ(v3, Vec3(1.1, 2.2, 0.1));
 	ANKI_TEST_EXPECT_EQ(v3, Vec3(1.1, 2.2, 0.1));
 }
 }
+
+ANKI_TEST(Script, LuaBinderThreads)
+{
+	ScriptManager sm;
+	ANKI_TEST_EXPECT_NO_ERR(sm.init(allocAligned, nullptr, nullptr, nullptr));
+
+	ScriptEnvironmentPtr env;
+	ANKI_TEST_EXPECT_NO_ERR(sm.newScriptEnvironment(env));
+
+	static const char* script = R"(
+vec = Vec4.new(0, 0, 0, 0)
+	
+function myFunc()
+	vec:setX(vec:getX() + 1)
+	logi(string.format("The number is %f", vec:getX()))
+end
+)";
+
+	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script));
+
+	static const char* script1 = R"(
+myFunc()
+)";
+
+	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script1));
+	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script1));
+}