Browse Source

Add Data:performAtomic to lock a mutex while using a Data object.

Sasha Szpakowski 1 year ago
parent
commit
ae6800e0e0

+ 17 - 0
src/common/Data.cpp

@@ -20,10 +20,27 @@
 
 // LOVE
 #include "Data.h"
+#include "thread/threads.h"
 
 namespace love
 {
 
 love::Type Data::type("Data", &Object::type);
 
+Data::~Data()
+{
+	delete mutex;
+}
+
+static void createMutex(love::thread::Mutex **mutexAddress)
+{
+	*mutexAddress = love::thread::newMutex();
+}
+
+love::thread::Mutex *Data::getMutex()
+{
+	std::call_once(mutexCreated, createMutex, &mutex);
+	return mutex;
+}
+
 } // love

+ 19 - 5
src/common/Data.h

@@ -22,15 +22,20 @@
 #define LOVE_DATA_H
 
 // LOVE
-#include "config.h"
 #include "Object.h"
 
 // C
 #include <stddef.h>
+#include <mutex>
 
 namespace love
 {
 
+namespace thread
+{
+class Mutex;
+}
+
 /**
  * This class is a simple abstraction over all objects which contain data.
  **/
@@ -40,10 +45,8 @@ public:
 
 	static love::Type type;
 
-	/**
-	 * Destructor.
-	 **/
-	virtual ~Data() {}
+	Data() {};
+	virtual ~Data();
 
 	/**
 	 * Creates a duplicate of Data derived class instance.
@@ -60,6 +63,17 @@ public:
 	 **/
 	virtual size_t getSize() const = 0;
 
+	/**
+	 * Gets the Mutex associated with this Data object. Creates it in a thread-
+	 * safe manner if necessary.
+	 **/
+	love::thread::Mutex *getMutex();
+
+private:
+
+	love::thread::Mutex *mutex = nullptr;
+	std::once_flag mutexCreated;
+
 }; // Data
 
 } // love

+ 22 - 0
src/modules/data/wrap_Data.cpp

@@ -20,6 +20,7 @@
 
 #include "wrap_Data.h"
 #include "common/int.h"
+#include "thread/threads.h"
 
 // Put the Lua code directly into a raw string literal.
 static const char data_lua[] =
@@ -78,6 +79,26 @@ int w_Data_getSize(lua_State *L)
 	return 1;
 }
 
+int w_Data_performAtomic(lua_State *L)
+{
+	Data *t = luax_checkdata(L, 1);
+	int err = 0;
+
+	{
+		love::thread::Lock lock(t->getMutex());
+		// call the function, passing any user-specified arguments.
+		err = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0);
+	}
+
+	// Unfortunately, this eats the stack trace, too bad.
+	if (err != 0)
+		return lua_error(L);
+
+	// The function and everything after it in the stack are eaten by the pcall,
+	// leaving only the Data object. Everything else is a return value.
+	return lua_gettop(L) - 1;
+}
+
 template <typename T>
 static int w_Data_getT(lua_State* L)
 {
@@ -170,6 +191,7 @@ const luaL_Reg w_Data_functions[] =
 	{ "getPointer", w_Data_getPointer },
 	{ "getFFIPointer", w_Data_getFFIPointer },
 	{ "getSize", w_Data_getSize },
+	{ "performAtomic", w_Data_performAtomic },
 	{ "getFloat", w_Data_getFloat },
 	{ "getDouble", w_Data_getDouble },
 	{ "getInt8", w_Data_getInt8 },

+ 0 - 5
src/modules/image/ImageData.cpp

@@ -764,11 +764,6 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in
 	}
 }
 
-love::thread::Mutex *ImageData::getMutex() const
-{
-	return mutex;
-}
-
 size_t ImageData::getPixelSize() const
 {
 	return getPixelFormatBlockSize(format);

+ 0 - 4
src/modules/image/ImageData.h

@@ -110,8 +110,6 @@ public:
 	 **/
 	love::filesystem::FileData *encode(FormatHandler::EncodedFormat format, const char *filename, bool writefile) const;
 
-	love::thread::Mutex *getMutex() const;
-
 	// Implements ImageDataBase.
 	ImageData *clone() const override;
 	void *getData() const override;
@@ -142,8 +140,6 @@ private:
 	// The actual data.
 	unsigned char *data = nullptr;
 
-	love::thread::MutexRef mutex;
-
 	// The format handler that was used to decode the ImageData. We need to know
 	// this so we can properly delete memory allocated by the decoder.
 	StrongRef<FormatHandler> decodeHandler;