diff --git a/src/common/Data.cpp b/src/common/Data.cpp index 9da33a2a2..d3f7bdd6d 100644 --- a/src/common/Data.cpp +++ b/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 diff --git a/src/common/Data.h b/src/common/Data.h index 479a4a6d6..bb19b66cb 100644 --- a/src/common/Data.h +++ b/src/common/Data.h @@ -22,15 +22,20 @@ #define LOVE_DATA_H // LOVE -#include "config.h" #include "Object.h" // C #include +#include namespace love { +namespace thread +{ +class Mutex; +} + /** * This class is a simple abstraction over all objects which contain data. **/ @@ -40,10 +45,8 @@ class Data : public Object static love::Type type; - /** - * Destructor. - **/ - virtual ~Data() {} + Data() {}; + virtual ~Data(); /** * Creates a duplicate of Data derived class instance. @@ -60,6 +63,17 @@ class Data : public Object **/ 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 diff --git a/src/modules/data/wrap_Data.cpp b/src/modules/data/wrap_Data.cpp index 586daae1e..f9b144ebd 100644 --- a/src/modules/data/wrap_Data.cpp +++ b/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 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 }, diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index faff29046..7c2c5205c 100644 --- a/src/modules/image/ImageData.cpp +++ b/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); diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index 552d3b0a2..5eb800f4d 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -110,8 +110,6 @@ class ImageData : public ImageDataBase **/ 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 @@ class ImageData : public ImageDataBase // 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 decodeHandler;