Prechádzať zdrojové kódy

Added a spin lock
WIP on events being thread safe
Added memory stack allocation as an option to normal allocation methods

Marko Pintera 11 rokov pred
rodič
commit
400f46a477

+ 1 - 0
BansheeEngine.sln

@@ -22,6 +22,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CamelotGLRenderSystem", "Ca
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1D081E5A-615A-4C06-B2DF-0D8D9390DE02}"
 	ProjectSection(SolutionItems) = preProject
+		BoostPort.txt = BoostPort.txt
 		CSharpWrap.txt = CSharpWrap.txt
 		Dependencies.txt = Dependencies.txt
 		DrawHelper.txt = DrawHelper.txt

+ 20 - 0
BoostPort.txt

@@ -0,0 +1,20 @@
+Events:
+ - Locking currently doesn't work properly. I need to use stack allocation to temporarily allocate std::functions when triggering an event
+ - Add support for variadic number of parameters. Initially just by using boost preprocessor like in other places.
+  - Note for events and its function style arguments: "class variadic_extended_signature<R (Args...)>"
+
+Replace boost::any from Any in POCO
+Replace boost::uid from UUID in POCO
+Temporarily make filesystem use VS filesystem header
+
+
+
+--------------
+Once ported to VS:
+ - Remove boost preprocessor macros and use variadic templates
+ - Remove ::type extensions from vectors
+ - Port filesystem from VS implementation to custom one
+
+--------------
+Other:
+ - std::function allocates memory yet I'm not using a custom allocator for it.

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -267,6 +267,7 @@
     <ClCompile Include="Source\CmUUID.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
     <ClInclude Include="Include\BsEvent.h" />
+    <ClInclude Include="Include\BsSpinLock.h" />
     <ClInclude Include="Include\BsTaskScheduler.h" />
     <ClInclude Include="Include\BsThreadPool.h" />
     <ClInclude Include="Include\CmAsyncOp.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -237,6 +237,9 @@
     <ClInclude Include="Include\BsEvent.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsSpinLock.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmMath.cpp">

+ 29 - 9
CamelotUtility/Include/BsEvent.h

@@ -49,26 +49,45 @@ namespace BansheeEngine
 
 		HEvent connect(std::function<RetType(P0)> func)
 		{
-			// TODO - Lock
-
 			ConnectionData* connData = cm_new<ConnectionData>(func);
-			mConnections.push_back(connData);
 
+			{
+				ScopedSpinLock lock;
+				mConnections.push_back(connData);
+			}
+			
 			return HEvent(connData, this, &Event1::disconnectCallback);
 		}
 
 		void operator() (P0 args)
 		{
-			// TODO - Lock each call separately using a spin lock
+			SpinLock lock;
+
+			// TODO - This isn't correct as iterator isn't locked while function is executing
+
+			// Fix by:
+			//  - Using stack alloc allocate N std::function objects
+			//  - Create std::function objects using a stack allocator internally
+
+
+			lock.lock();
 
 			for(auto& connection : mConnections)
-				connection->func(args);
+			{
+				std::function<RetType(P0)> func = connection->func;
+				lock.unlock();
+
+				func(args);
+
+				lock.lock();
+			}
+			lock.unlock();
 		}
 
 		void clear()
 		{
-			// TODO - Lock
-			
+			ScopedSpinLock lock;
+
 			for(auto& connection : mConnections)
 			{
 				cm_delete(connection);
@@ -79,7 +98,8 @@ namespace BansheeEngine
 
 		bool empty()
 		{
-			// TODO - Lock
+			ScopedSpinLock lock;
+
 			return mConnections.size() == 0;
 		}
 
@@ -99,7 +119,7 @@ namespace BansheeEngine
 
 		void disconnect(ConnectionData* connData)
 		{
-			// TODO - Lock
+			ScopedSpinLock lock;
 
 			for(auto& iter = mConnections.begin(); iter != mConnections.end(); ++iter)
 			{

+ 46 - 0
CamelotUtility/Include/BsSpinLock.h

@@ -0,0 +1,46 @@
+#pragma once
+
+#include <atomic>
+
+namespace BansheeEngine
+{
+	class SpinLock
+	{
+	public:
+		SpinLock()
+		{
+			mLock.clear(std::memory_order_relaxed);
+		}
+
+		void lock()
+		{
+			while(mLock.test_and_set(std::memory_order_acquire))
+			{ }
+		}
+
+		void unlock()
+		{
+			mLock.clear(std::memory_order_release);
+		}
+
+	private:
+		std::atomic_flag mLock;
+	};
+
+	class ScopedSpinLock
+	{
+	public:
+		ScopedSpinLock()
+		{
+			mLock.lock();
+		}
+
+		~ScopedSpinLock()
+		{
+			mLock.unlock();
+		}
+
+	private:
+		SpinLock mLock;
+	};
+}

+ 39 - 0
CamelotUtility/Include/CmMemStack.h

@@ -290,4 +290,43 @@ namespace BansheeEngine
 	 * @copydoc	MemoryStackInternal::dealloc()
 	 */
 	CM_UTILITY_EXPORT inline void stackDeallocLast(void* data);
+
+	/**
+	* @brief	Allows use of a stack allocator by using normal new/delete/free/dealloc operators.
+	* 			
+	* @see		MemStack
+	*/
+	class StackAlloc
+	{ };
+
+	/**
+	* @brief	Specialized memory allocator implementations that allows use of a 
+	* 			stack allocator in normal new/delete/free/dealloc operators.
+	* 			
+	* @see		MemStack
+	*/
+	template<>
+	class MemoryAllocator<StackAlloc> : public MemoryAllocatorBase
+	{
+	public:
+		static inline void* allocate(size_t bytes)
+		{
+			stackAlloc((UINT32)bytes);
+		}
+
+		static inline void* allocateArray(size_t bytes, UINT32 count)
+		{
+			return stackAlloc((UINT32)(bytes * count));
+		}
+
+		static inline void free(void* ptr)
+		{
+			stackDeallocLast(ptr);
+		}
+
+		static inline void freeArray(void* ptr, UINT32 count)
+		{
+			stackDeallocLast(ptr);
+		}
+	};
 }

+ 0 - 1
CamelotUtility/Include/CmMemoryAllocator.h

@@ -122,7 +122,6 @@ namespace BansheeEngine
 	class PoolAlloc
 	{ };
 
-
 	/**
 	 * @brief	Allocates the specified number of bytes.
 	 */

+ 1 - 0
CamelotUtility/Include/CmThreadDefines.h

@@ -8,6 +8,7 @@
 #include <chrono>
 #include <mutex>
 #include <condition_variable>
+#include "BsSpinLock.h"
 
 #define CM_AUTO_MUTEX mutable std::mutex CM_AUTO_MUTEX_NAME;
 #define CM_LOCK_AUTO_MUTEX std::unique_lock<std::mutex> cmAutoMutexLock(CM_AUTO_MUTEX_NAME);