aboutsummaryrefslogtreecommitdiff
path: root/src/network/connection.cpp
Commit message (Expand)AuthorAge
* Use the outgoing split sequence number for every outgoing packet (#4864)Rogier-52016-12-29
* Sapier's fix for the RESEND RELIABLE problem (#4170)Robert Kiraly2016-06-03
* Tolerate packet reordering in the early init processest312016-05-22
* Always use errorstream for DEBUG_EXCEPTION_HANDLERShadowNinja2015-10-14
* Use warningstream for log messages with WARNINGShadowNinja2015-10-14
* Change i++ to ++iDavid Jones2015-08-25
* Clean up threadingShadowNinja2015-08-23
* Remove unused function from connection.{cpp,h}nerzhul2015-08-15
* connection: Make assertions non-fatal for received datakwolekr2015-08-05
* connection.cpp: remove unused constructorLoic Blot2015-07-14
* Move globals from main.cpp to more sane locationsCraig Robbins2015-04-01
* Connection::Receive(): receive Network Packet instead of SharedBuffer<u8>.Loic Blot2015-03-31
* RunCommandQueues: little optimizationLoic Blot2015-03-31
* Typo in getOutgoingSequenceNumber => successfull to successfulLoic Blot2015-03-31
* queued_commands must be a std::deque. RunCommandQueues needs to push packet o...Loic Blot2015-03-29
* Remove unused ConnectionCommand::sendToAll function. NetworkPacket::oldForgeP...Loic Blot2015-03-22
* Replace NetworkPacket pointers to referencesLoic Blot2015-03-13
* For usages of assert() that are meant to persist in Release builds (when NDEB...Craig Robbins2015-03-07
* Remove Queue class which uses std::list and use native std::queueLoic Blot2015-03-05
* Fix some memory leaks on packet sending.Loic Blot2015-02-21
* [Patch 2/4] Network rework: packet writing, sending and cleanupsLoic Blot2015-02-16
a id='n209' href='#n209'>209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef UTIL_THREAD_HEADER
#define UTIL_THREAD_HEADER

#include "../irrlichttypes.h"
#include <jthread.h>
#include <jmutex.h>
#include <jmutexautolock.h>

template<typename T>
class MutexedVariable
{
public:
	MutexedVariable(T value):
		m_value(value)
	{
		m_mutex.Init();
	}

	T get()
	{
		JMutexAutoLock lock(m_mutex);
		return m_value;
	}

	void set(T value)
	{
		JMutexAutoLock lock(m_mutex);
		m_value = value;
	}
	
	// You'll want to grab this in a SharedPtr
	JMutexAutoLock * getLock()
	{
		return new JMutexAutoLock(m_mutex);
	}
	
	// You pretty surely want to grab the lock when accessing this
	T m_value;

private:
	JMutex m_mutex;
};

/*
	A base class for simple background thread implementation
*/

class SimpleThread : public JThread
{
	bool run;
	JMutex run_mutex;

public:

	SimpleThread():
		JThread(),
		run(true)
	{
		run_mutex.Init();
	}

	virtual ~SimpleThread()
	{}

	virtual void * Thread() = 0;

	bool getRun()
	{
		JMutexAutoLock lock(run_mutex);
		return run;
	}
	void setRun(bool a_run)
	{
		JMutexAutoLock lock(run_mutex);
		run = a_run;
	}

	void stop()
	{
		setRun(false);
		while(IsRunning())
			sleep_ms(100);
	}
};

/*
	A single worker thread - multiple client threads queue framework.
*/

template<typename Caller, typename Data>
class CallerInfo
{
public:
	Caller caller;
	Data data;
};

template<typename Key, typename T, typename Caller, typename CallerData>
class GetResult
{
public:
	Key key;
	T item;
	std::list<CallerInfo<Caller, CallerData> > callers;
};

template<typename Key, typename T, typename Caller, typename CallerData>
class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
{
};

template<typename Key, typename T, typename Caller, typename CallerData>
class GetRequest
{
public:
	GetRequest()
	{
		dest = NULL;
	}
	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
	{
		dest = a_dest;
	}
	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
			Key a_key)
	{
		dest = a_dest;
		key = a_key;
	}
	~GetRequest()
	{
	}
	
	Key key;
	ResultQueue<Key, T, Caller, CallerData> *dest;
	std::list<CallerInfo<Caller, CallerData> > callers;
};

template<typename Key, typename T, typename Caller, typename CallerData>
class RequestQueue
{
public:
	bool empty()
	{
		return m_queue.empty();
	}

	void add(Key key, Caller caller, CallerData callerdata,
			ResultQueue<Key, T, Caller, CallerData> *dest)
	{
		JMutexAutoLock lock(m_queue.getMutex());
		
		/*
			If the caller is already on the list, only update CallerData
		*/
		for(typename std::list< GetRequest<Key, T, Caller, CallerData> >::iterator
				i = m_queue.getList().begin();
				i != m_queue.getList().end(); ++i)
		{
			GetRequest<Key, T, Caller, CallerData> &request = *i;

			if(request.key == key)
			{
				for(typename std::list< CallerInfo<Caller, CallerData> >::iterator
						i = request.callers.begin();
						i != request.callers.end(); ++i)
				{
					CallerInfo<Caller, CallerData> &ca = *i;
					if(ca.caller == caller)
					{
						ca.data = callerdata;
						return;
					}
				}
				CallerInfo<Caller, CallerData> ca;
				ca.caller = caller;
				ca.data = callerdata;
				request.callers.push_back(ca);
				return;
			}
		}

		/*
			Else add a new request to the queue
		*/

		GetRequest<Key, T, Caller, CallerData> request;
		request.key = key;
		CallerInfo<Caller, CallerData> ca;
		ca.caller = caller;
		ca.data = callerdata;
		request.callers.push_back(ca);
		request.dest = dest;
		
		m_queue.getList().push_back(request);
	}

	GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
	{
		return m_queue.pop_front(wait_if_empty);
	}

private:
	MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
};

#endif