Browse Source

Simplify love.audio's Pool class

Move most logic back to Source. Pool now simply contains a list of playing
sources and a mutex. Also gets rid of the pause/pauseAtomic duplication in
Source, since it can now request a lock from Pool itself.

--HG--
branch : minor
Bart van Strien 8 years ago
parent
commit
03b863d788

+ 10 - 0
src/common/config.h

@@ -86,6 +86,16 @@
 #	define LOVE_UNUSED(x) (void)sizeof(x)
 #	define LOVE_UNUSED(x) (void)sizeof(x)
 #endif
 #endif
 
 
+
+// Warn on unused return values
+#ifdef __GNUC__
+#	define LOVE_WARN_UNUSED __attribute__((warn_unused_result))
+#elif _MSC_VER
+#	define LOVE_WARN_UNUSED _Check_return_
+#else
+#	define LOVE_WARN_UNUSED
+#endif
+
 #ifndef LOVE_BUILD
 #ifndef LOVE_BUILD
 #	define LOVE_BUILD
 #	define LOVE_BUILD
 #	define LOVE_BUILD_STANDALONE
 #	define LOVE_BUILD_STANDALONE

+ 5 - 5
src/modules/audio/openal/Audio.cpp

@@ -240,7 +240,7 @@ bool Audio::play(love::audio::Source *source)
 
 
 bool Audio::play(const std::vector<love::audio::Source*> &sources)
 bool Audio::play(const std::vector<love::audio::Source*> &sources)
 {
 {
-	return pool->play(sources);
+	return Source::play(sources);
 }
 }
 
 
 void Audio::stop(love::audio::Source *source)
 void Audio::stop(love::audio::Source *source)
@@ -250,12 +250,12 @@ void Audio::stop(love::audio::Source *source)
 
 
 void Audio::stop(const std::vector<love::audio::Source*> &sources)
 void Audio::stop(const std::vector<love::audio::Source*> &sources)
 {
 {
-	return pool->stop(sources);
+	return Source::stop(sources);
 }
 }
 
 
 void Audio::stop()
 void Audio::stop()
 {
 {
-	pool->stop();
+	return Source::stop(pool);
 }
 }
 
 
 void Audio::pause(love::audio::Source *source)
 void Audio::pause(love::audio::Source *source)
@@ -265,12 +265,12 @@ void Audio::pause(love::audio::Source *source)
 
 
 void Audio::pause(const std::vector<love::audio::Source*> &sources)
 void Audio::pause(const std::vector<love::audio::Source*> &sources)
 {
 {
-	return pool->pause(sources);
+	return Source::pause(sources);
 }
 }
 
 
 std::vector<love::audio::Source*> Audio::pause()
 std::vector<love::audio::Source*> Audio::pause()
 {
 {
-	return pool->pause();
+	return Source::pause(pool);
 }
 }
 
 
 void Audio::setVolume(float volume)
 void Audio::setVolume(float volume)

+ 29 - 176
src/modules/audio/openal/Pool.cpp

@@ -73,7 +73,7 @@ Pool::Pool()
 
 
 Pool::~Pool()
 Pool::~Pool()
 {
 {
-	stop();
+	Source::stop(this);
 
 
 	// Free all sources.
 	// Free all sources.
 	alDeleteSources(totalSources, sources);
 	alDeleteSources(totalSources, sources);
@@ -103,20 +103,9 @@ void Pool::update()
 {
 {
 	thread::Lock lock(mutex);
 	thread::Lock lock(mutex);
 
 
-	std::map<Source *, ALuint>::iterator i = playing.begin();
-
-	while (i != playing.end())
-	{
-		if (!i->first->update())
-		{
-			i->first->stopAtomic();
-			i->first->release();
-			available.push(i->second);
-			playing.erase(i++);
-		}
-		else
-			i++;
-	}
+	for (const auto &i : playing)
+		if (!i.first->update())
+			releaseSource(i.first);
 }
 }
 
 
 int Pool::getSourceCount() const
 int Pool::getSourceCount() const
@@ -129,19 +118,14 @@ int Pool::getMaxSources() const
 	return totalSources;
 	return totalSources;
 }
 }
 
 
-bool Pool::assignSource(Source *source, ALuint &out, char *wasPlaying)
+bool Pool::assignSource(Source *source, ALuint &out, char &wasPlaying)
 {
 {
 	out = 0;
 	out = 0;
 
 
 	if (findSource(source, out))
 	if (findSource(source, out))
-	{
-		if (wasPlaying)
-			*wasPlaying = true;
-		return true;
-	}
+		return wasPlaying = true;
 
 
-	if (wasPlaying)
-		*wasPlaying = false;
+	wasPlaying = false;
 
 
 	if (available.empty())
 	if (available.empty())
 		return false;
 		return false;
@@ -154,177 +138,46 @@ bool Pool::assignSource(Source *source, ALuint &out, char *wasPlaying)
 	return true;
 	return true;
 }
 }
 
 
-bool Pool::play(Source *source)
+bool Pool::releaseSource(Source *source, bool stop)
 {
 {
-	thread::Lock lock(mutex);
-	ALuint out;
+	ALuint s;
 
 
-	char wasPlaying;
-	if (!assignSource(source, out, &wasPlaying))
-		return false;
-
-	if (!wasPlaying)
-		return source->playAtomic(out);
-	else
-	{
-		source->resumeAtomic();
-		return true;
-	}
-}
-
-bool Pool::play(const std::vector<love::audio::Source*> &sources)
-{
-	thread::Lock lock(mutex);
-
-	std::vector<ALuint> ids(sources.size());
-	// NOTE: not bool, because std::vector<bool> is implemented as a bitvector
-	// which means no pointers can be created.
-	std::vector<char> wasPlaying(sources.size());
-
-	for (size_t i = 0; i < sources.size(); i++)
-	{
-		Source *source = (Source*) sources[i];
-		if (!assignSource(source, ids[i], &wasPlaying[i]))
-		{
-			// Now we need to release the resources we had already allocated
-			for (size_t j = 0; j < sources.size(); j++)
-				if (!wasPlaying[j])
-					release((Source*) sources[j]);
-			return false;
-		}
-	}
-
-	return Source::playAtomic(sources, ids, wasPlaying);
-}
-
-void Pool::stop()
-{
-	thread::Lock lock(mutex);
-	for (const auto &i : playing)
-	{
-		i.first->stopAtomic();
-		i.first->release();
-		available.push(i.second);
-	}
-
-	playing.clear();
-}
-
-void Pool::stop(Source *source)
-{
-	thread::Lock lock(mutex);
-	removeSource(source);
-}
-
-void Pool::stop(const std::vector<love::audio::Source*> &sources)
-{
-	thread::Lock lock(mutex);
-	Source::stopAtomic(sources);
-}
-
-std::vector<love::audio::Source*> Pool::pause()
-{
-	thread::Lock lock(mutex);
-
-	std::vector<love::audio::Source*> werePlaying;
-	werePlaying.reserve(playing.size());
-
-	for (const auto &i : playing)
-	{
-		if (!i.first->isPlaying())
-			continue;
-		werePlaying.push_back(i.first);
-		i.first->pauseAtomic();
-	}
-
-	return werePlaying;
-}
-
-void Pool::pause(Source *source)
-{
-	thread::Lock lock(mutex);
-	ALuint out;
-	if (findSource(source, out))
-		source->pauseAtomic();
-}
-
-void Pool::pause(const std::vector<love::audio::Source*> &sources)
-{
-	thread::Lock lock(mutex);
-	Source::pauseAtomic(sources);
-}
-
-void Pool::release(Source *source)
-{
-	ALuint s = findi(source);
-
-	if (s != 0)
+	if (findSource(source, s))
 	{
 	{
+		if (stop)
+			source->stopAtomic();
+		source->release();
 		available.push(s);
 		available.push(s);
 		playing.erase(source);
 		playing.erase(source);
+		return true;
 	}
 	}
-}
-
-void Pool::seek(Source *source, float offset, void *unit)
-{
-	thread::Lock lock(mutex);
-	return source->seekAtomic(offset, unit);
-}
-
-float Pool::tell(Source *source, void *unit)
-{
-	thread::Lock lock(mutex);
-	return source->tellAtomic(unit);
-}
-
-double Pool::getDuration(Source *source, void *unit)
-{
-	thread::Lock lock(mutex);
-	return source->getDurationAtomic(unit);
-}
 
 
-bool Pool::queue(Source *source, void *data, ALsizei length)
-{
-	thread::Lock lock(mutex);
-	return source->queueAtomic(data, length);
+	return false;
 }
 }
 
 
-ALuint Pool::findi(const Source *source) const
+bool Pool::findSource(Source *source, ALuint &out)
 {
 {
-	std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
+	std::map<Source *, ALuint>::const_iterator i = playing.find(source);
 
 
-	if (i != playing.end())
-		return i->second;
+	if (i == playing.end())
+		return false;
 
 
-	return 0;
+	out = i->second;
+	return true;
 }
 }
 
 
-bool Pool::findSource(Source *source, ALuint &out)
+thread::Lock Pool::lock()
 {
 {
-	std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
-
-	bool found = i != playing.end();
-
-	if (found)
-		out = i->second;
-
-	return found;
+	return thread::Lock(mutex);
 }
 }
 
 
-bool Pool::removeSource(Source *source)
+std::vector<love::audio::Source*> Pool::getPlayingSources()
 {
 {
-	std::map<Source *, ALuint>::iterator i = playing.find((Source *)source);
-
-	if (i != playing.end())
-	{
-		source->stopAtomic();
-		available.push(i->second);
-		playing.erase(i++);
-		source->release();
-		return true;
-	}
-
-	return false;
+	std::vector<love::audio::Source*> sources;
+	sources.reserve(playing.size());
+	for (auto &i : playing)
+		sources.push_back(i.first);
+	return sources;
 }
 }
 
 
 } // openal
 } // openal

+ 6 - 19
src/modules/audio/openal/Pool.h

@@ -83,33 +83,20 @@ public:
 	int getSourceCount() const;
 	int getSourceCount() const;
 	int getMaxSources() const;
 	int getMaxSources() const;
 
 
-	bool play(Source *source);
-	void stop();
-	void stop(Source *source);
-	std::vector<love::audio::Source*> pause();
-	void pause(Source *source);
-	void seek(Source *source, float offset, void *unit);
-	float tell(Source *source, void *unit);
-	double getDuration(Source *source, void *unit);
-	bool queue(Source *source, void *data, ALsizei length);
-
-	bool play(const std::vector<love::audio::Source*> &sources);
-	void stop(const std::vector<love::audio::Source*> &sources);
-	void pause(const std::vector<love::audio::Source*> &sources);
-
 private:
 private:
 
 
+	friend class Source;
+	LOVE_WARN_UNUSED thread::Lock lock();
+	std::vector<love::audio::Source*> getPlayingSources();
+
 	/**
 	/**
 	 * Makes the specified OpenAL source available for use.
 	 * Makes the specified OpenAL source available for use.
 	 * @param source The OpenAL source.
 	 * @param source The OpenAL source.
 	 **/
 	 **/
-	void release(Source *source);
-
-	ALuint findi(const Source *source) const;
+	bool releaseSource(Source *source, bool stop = true);
 
 
-	bool assignSource(Source *source, ALuint &out, char *wasPlaying = nullptr);
+	bool assignSource(Source *source, ALuint &out, char &wasPlaying);
 	bool findSource(Source *source, ALuint &out);
 	bool findSource(Source *source, ALuint &out);
-	bool removeSource(Source *source);
 
 
 	// Maximum possible number of OpenAL sources the pool attempts to generate.
 	// Maximum possible number of OpenAL sources the pool attempts to generate.
 	static const int MAX_SOURCES = 64;
 	static const int MAX_SOURCES = 64;

+ 84 - 46
src/modules/audio/openal/Source.cpp

@@ -30,6 +30,8 @@
 
 
 #define audiomodule() (Module::getInstance<Audio>(Module::M_AUDIO))
 #define audiomodule() (Module::getInstance<Audio>(Module::M_AUDIO))
 
 
+using love::thread::Lock;
+
 namespace love
 namespace love
 {
 {
 namespace audio
 namespace audio
@@ -234,8 +236,7 @@ Source::Source(const Source &s)
 
 
 Source::~Source()
 Source::~Source()
 {
 {
-	if (valid)
-		pool->stop(this);
+	stop();
 
 
 	if (sourceType != TYPE_STATIC)
 	if (sourceType != TYPE_STATIC)
 		alDeleteBuffers(MAX_BUFFERS, streamBuffers);
 		alDeleteBuffers(MAX_BUFFERS, streamBuffers);
@@ -257,19 +258,34 @@ love::audio::Source *Source::clone()
 
 
 bool Source::play()
 bool Source::play()
 {
 {
-	valid = pool->play(this);
-	return valid;
+	Lock l = pool->lock();
+	ALuint out;
+
+	char wasPlaying;
+	if (!pool->assignSource(this, out, wasPlaying))
+		return valid = false;
+
+	if (!wasPlaying)
+		return valid = playAtomic(out);
+
+	resumeAtomic();
+	return valid = true;
 }
 }
 
 
 void Source::stop()
 void Source::stop()
 {
 {
-	if (valid)
-		pool->stop(this);
+	if (!valid)
+		return;
+
+	Lock l = pool->lock();
+	pool->releaseSource(this);
 }
 }
 
 
 void Source::pause()
 void Source::pause()
 {
 {
-	pool->pause(this);
+	Lock l = pool->lock();
+	if (pool->isPlaying(this))
+		pauseAtomic();
 }
 }
 
 
 bool Source::isPlaying() const
 bool Source::isPlaying() const
@@ -343,7 +359,7 @@ bool Source::update()
 				return true;
 				return true;
 			}
 			}
 			return false;
 			return false;
-		case TYPE_QUEUE:
+		case TYPE_QUEUE: 
 		{
 		{
 			ALint processed;
 			ALint processed;
 			ALuint buffers[MAX_BUFFERS];
 			ALuint buffers[MAX_BUFFERS];
@@ -409,11 +425,13 @@ float Source::getVolume() const
 	return volume;
 	return volume;
 }
 }
 
 
-void Source::seekAtomic(float offset, void *unit)
+void Source::seek(float offset, Source::Unit unit)
 {
 {
+	Lock l = pool->lock();
+
 	float offsetSamples, offsetSeconds;
 	float offsetSamples, offsetSeconds;
 
 
-	switch (*((Source::Unit *) unit))
+	switch (unit)
 	{
 	{
 	case Source::UNIT_SAMPLES:
 	case Source::UNIT_SAMPLES:
 		offsetSamples = offset;
 		offsetSamples = offset;
@@ -492,16 +510,13 @@ void Source::seekAtomic(float offset, void *unit)
 	this->offsetSeconds = offsetSeconds;
 	this->offsetSeconds = offsetSeconds;
 }
 }
 
 
-void Source::seek(float offset, Source::Unit unit)
+float Source::tell(Source::Unit unit)
 {
 {
-	return pool->seek(this, offset, &unit);
-}
+	Lock l = pool->lock();
 
 
-float Source::tellAtomic(void *unit) const
-{
 	float offset = 0.0f;
 	float offset = 0.0f;
 
 
-	switch (*((Source::Unit *) unit))
+	switch (unit)
 	{
 	{
 	case Source::UNIT_SAMPLES:
 	case Source::UNIT_SAMPLES:
 		if (valid)
 		if (valid)
@@ -519,14 +534,9 @@ float Source::tellAtomic(void *unit) const
 	return offset;
 	return offset;
 }
 }
 
 
-float Source::tell(Source::Unit unit)
-{
-	return pool->tell(this, &unit);
-}
-
-double Source::getDurationAtomic(void *vunit)
+double Source::getDuration(Unit unit)
 {
 {
-	Unit unit = *(Unit *) vunit;
+	Lock l = pool->lock();
 
 
 	switch (sourceType)
 	switch (sourceType)
 	{
 	{
@@ -564,11 +574,6 @@ double Source::getDurationAtomic(void *vunit)
 	return 0.0;
 	return 0.0;
 }
 }
 
 
-double Source::getDuration(Unit unit)
-{
-	return pool->getDuration(this, &unit);
-}
-
 void Source::setPosition(float *v)
 void Source::setPosition(float *v)
 {
 {
 	if (channels > 1)
 	if (channels > 1)
@@ -716,11 +721,8 @@ bool Source::queue(void *data, size_t length, int dataSampleRate, int dataBitDep
 	if (length == 0)
 	if (length == 0)
 		return true;
 		return true;
 
 
-	return pool->queue(this, data, (ALsizei)length);
-}
+	Lock l = pool->lock();
 
 
-bool Source::queueAtomic(void *data, ALsizei length)
-{
 	if (valid)
 	if (valid)
 	{
 	{
 		ALuint buffer = unusedBufferPeek();
 		ALuint buffer = unusedBufferPeek();
@@ -887,10 +889,6 @@ bool Source::playAtomic(ALuint source)
 	if (sourceType != TYPE_STREAM)
 	if (sourceType != TYPE_STREAM)
 		offsetSamples = offsetSeconds = 0;
 		offsetSamples = offsetSeconds = 0;
 
 
-	//this is set to success state afterwards anyway, but setting it here
-	//to true preemptively avoids race condition with update bug
-	valid = true;
-
 	return success;
 	return success;
 }
 }
 
 
@@ -919,26 +917,40 @@ void Source::resumeAtomic()
 	}
 	}
 }
 }
 
 
-bool Source::playAtomic(const std::vector<love::audio::Source*> &sources, const std::vector<ALuint> &ids, const std::vector<char> &wasPlaying)
+bool Source::play(const std::vector<love::audio::Source*> &sources)
 {
 {
 	if (sources.size() == 0)
 	if (sources.size() == 0)
 		return true;
 		return true;
 
 
+	Pool *pool = ((Source*) sources[0])->pool;
+	Lock l = pool->lock();
+
+	// NOTE: not bool, because std::vector<bool> is implemented as a bitvector
+	// which means no bool references can be created.
+	std::vector<char> wasPlaying(sources.size());
+	std::vector<ALuint> ids(sources.size());
+
+	for (size_t i = 0; i < sources.size(); i++)
+	{
+		if (!pool->assignSource((Source*) sources[i], ids[i], wasPlaying[i]))
+		{
+			for (size_t j = 0; j < i; j++)
+				if (!wasPlaying[j])
+					pool->releaseSource((Source*) sources[j], false);
+			return false;
+		}
+	}
+
 	std::vector<ALuint> toPlay;
 	std::vector<ALuint> toPlay;
 	toPlay.reserve(sources.size());
 	toPlay.reserve(sources.size());
 	for (size_t i = 0; i < sources.size(); i++)
 	for (size_t i = 0; i < sources.size(); i++)
 	{
 	{
-		Source *source = (Source*) sources[i];
-		// Paused sources have wasPlaying set to true, so do this first
-		if (!source->isPlaying())
-			toPlay.push_back(ids[i]);
-
-		// If it wasn't playing (nor paused), we have just allocated a new
-		// source
 		if (wasPlaying[i])
 		if (wasPlaying[i])
 			continue;
 			continue;
+		Source *source = (Source*) sources[i];
 		source->source = ids[i];
 		source->source = ids[i];
 		source->prepareAtomic();
 		source->prepareAtomic();
+		toPlay.push_back(ids[i]);
 	}
 	}
 
 
 	alGetError();
 	alGetError();
@@ -957,11 +969,14 @@ bool Source::playAtomic(const std::vector<love::audio::Source*> &sources, const
 	return success;
 	return success;
 }
 }
 
 
-void Source::stopAtomic(const std::vector<love::audio::Source*> &sources)
+void Source::stop(const std::vector<love::audio::Source*> &sources)
 {
 {
 	if (sources.size() == 0)
 	if (sources.size() == 0)
 		return;
 		return;
 
 
+	Pool *pool = ((Source*) sources[0])->pool;
+	Lock l = pool->lock();
+
 	std::vector<ALuint> sourceIds;
 	std::vector<ALuint> sourceIds;
 	sourceIds.reserve(sources.size());
 	sourceIds.reserve(sources.size());
 	for (auto &_source : sources)
 	for (auto &_source : sources)
@@ -978,14 +993,17 @@ void Source::stopAtomic(const std::vector<love::audio::Source*> &sources)
 		Source *source = (Source*) _source;
 		Source *source = (Source*) _source;
 		if (source->valid)
 		if (source->valid)
 			source->teardownAtomic();
 			source->teardownAtomic();
+		pool->releaseSource(source, false);
 	}
 	}
 }
 }
 
 
-void Source::pauseAtomic(const std::vector<love::audio::Source*> &sources)
+void Source::pause(const std::vector<love::audio::Source*> &sources)
 {
 {
 	if (sources.size() == 0)
 	if (sources.size() == 0)
 		return;
 		return;
 
 
+	Lock l = ((Source*) sources[0])->pool->lock();
+
 	std::vector<ALuint> sourceIds;
 	std::vector<ALuint> sourceIds;
 	sourceIds.reserve(sources.size());
 	sourceIds.reserve(sources.size());
 	for (auto &_source : sources)
 	for (auto &_source : sources)
@@ -998,6 +1016,26 @@ void Source::pauseAtomic(const std::vector<love::audio::Source*> &sources)
 	alSourcePausev((ALsizei) sources.size(), &sourceIds[0]);
 	alSourcePausev((ALsizei) sources.size(), &sourceIds[0]);
 }
 }
 
 
+std::vector<love::audio::Source*> Source::pause(Pool *pool)
+{
+	Lock l = pool->lock();
+	std::vector<love::audio::Source*> sources = pool->getPlayingSources();
+
+	auto newend = std::remove_if(sources.begin(), sources.end(), [](love::audio::Source* s) {
+		return !s->isPlaying();
+	});
+	sources.erase(newend, sources.end());
+
+	pause(sources);
+	return sources;
+}
+
+void Source::stop(Pool *pool)
+{
+	Lock l = pool->lock();
+	stop(pool->getPlayingSources());
+}
+
 void Source::reset()
 void Source::reset()
 {
 {
 	alSourcei(source, AL_BUFFER, AL_NONE);
 	alSourcei(source, AL_BUFFER, AL_NONE);

+ 6 - 7
src/modules/audio/openal/Source.h

@@ -114,11 +114,8 @@ public:
 	virtual float getPitch() const;
 	virtual float getPitch() const;
 	virtual void setVolume(float volume);
 	virtual void setVolume(float volume);
 	virtual float getVolume() const;
 	virtual float getVolume() const;
-	virtual void seekAtomic(float offset, void *unit);
 	virtual void seek(float offset, Unit unit);
 	virtual void seek(float offset, Unit unit);
-	virtual float tellAtomic(void *unit) const;
 	virtual float tell(Unit unit);
 	virtual float tell(Unit unit);
-	virtual double getDurationAtomic(void *unit);
 	virtual double getDuration(Unit unit);
 	virtual double getDuration(Unit unit);
 	virtual void setPosition(float *v);
 	virtual void setPosition(float *v);
 	virtual void getPosition(float *v) const;
 	virtual void getPosition(float *v) const;
@@ -157,7 +154,6 @@ public:
 
 
 	virtual int getFreeBufferCount() const;
 	virtual int getFreeBufferCount() const;
 	virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels);
 	virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels);
-	virtual bool queueAtomic(void *data, ALsizei length);
 
 
 	void prepareAtomic();
 	void prepareAtomic();
 	void teardownAtomic();
 	void teardownAtomic();
@@ -167,9 +163,12 @@ public:
 	void pauseAtomic();
 	void pauseAtomic();
 	void resumeAtomic();
 	void resumeAtomic();
 
 
-	static bool playAtomic(const std::vector<love::audio::Source*> &sources, const std::vector<ALuint> &ids, const std::vector<char> &wasPlaying);
-	static void stopAtomic(const std::vector<love::audio::Source*> &sources);
-	static void pauseAtomic(const std::vector<love::audio::Source*> &sources);
+	static bool play(const std::vector<love::audio::Source*> &sources);
+	static void stop(const std::vector<love::audio::Source*> &sources);
+	static void pause(const std::vector<love::audio::Source*> &sources);
+
+	static std::vector<love::audio::Source*> pause(Pool *pool);
+	static void stop(Pool *pool);
 
 
 private:
 private:
 
 

+ 8 - 1
src/modules/thread/threads.cpp

@@ -37,9 +37,16 @@ Lock::Lock(Mutex &m)
 	mutex->lock();
 	mutex->lock();
 }
 }
 
 
+Lock::Lock(Lock &&other)
+{
+	mutex = other.mutex;
+	other.mutex = nullptr;
+}
+
 Lock::~Lock()
 Lock::~Lock()
 {
 {
-	mutex->unlock();
+	if (mutex)
+		mutex->unlock();
 }
 }
 
 
 EmptyLock::EmptyLock()
 EmptyLock::EmptyLock()

+ 1 - 0
src/modules/thread/threads.h

@@ -57,6 +57,7 @@ class Lock
 public:
 public:
 	Lock(Mutex *m);
 	Lock(Mutex *m);
 	Lock(Mutex &m);
 	Lock(Mutex &m);
+	Lock(Lock &&other);
 	~Lock();
 	~Lock();
 
 
 private:
 private:

+ 1 - 1
src/scripts/nogame.lua.h

@@ -27,7 +27,7 @@ const unsigned char nogame_lua[] =
 
 
 	0x2d, 0x2d, 0x5b, 0x5b, 0x0a,
 	0x2d, 0x2d, 0x5b, 0x5b, 0x0a,
 	0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 
 	0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 
-	0x2d, 0x32, 0x30, 0x31, 0x36, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 
+	0x2d, 0x32, 0x30, 0x31, 0x37, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 
 	0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a,
 	0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a,
 	0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 
 	0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 
 	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, 
 	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77,