mirror of
https://github.com/minetest/minetest.git
synced 2024-11-30 03:23:45 +01:00
Clean up threading
* Rename everything. * Strip J prefix. * Change UpperCamelCase functions to lowerCamelCase. * Remove global (!) semaphore count mutex on OSX. * Remove semaphore count getter (unused, unsafe, depended on internal API functions on Windows, and used a hack on OSX). * Add `Atomic<type>`. * Make `Thread` handle thread names. * Add support for C++11 multi-threading. * Combine pthread and win32 sources. * Remove `ThreadStarted` (unused, unneeded). * Move some includes from the headers to the sources. * Move all of `Event` into its header (allows inlining with no new includes). * Make `Event` use `Semaphore` (except on Windows). * Move some porting functions into `Thread`. * Integrate logging with `Thread`. * Add threading test.
This commit is contained in:
parent
6a1047d8c1
commit
e4bff8be94
46
.gitignore
vendored
46
.gitignore
vendored
@ -36,45 +36,18 @@ doc/html/
|
|||||||
doc/doxygen_*
|
doc/doxygen_*
|
||||||
|
|
||||||
## Build files
|
## Build files
|
||||||
CMakeFiles/*
|
CMakeFiles
|
||||||
src/CMakeFiles/*
|
Makefile
|
||||||
src/Makefile
|
!build/android/Makefile
|
||||||
src/android_version_githash.h
|
cmake_install.cmake
|
||||||
src/android_version.h
|
|
||||||
src/cmake_config.h
|
|
||||||
src/cmake_config_githash.h
|
|
||||||
src/cmake_install.cmake
|
|
||||||
src/script/CMakeFiles/*
|
|
||||||
src/script/common/CMakeFiles/*
|
|
||||||
src/script/cpp_api/CMakeFiles/*
|
|
||||||
src/script/lua_api/CMakeFiles/*
|
|
||||||
src/util/CMakeFiles/*
|
|
||||||
src/unittest/CMakeFiles/*
|
|
||||||
src/jthread/CMakeFiles/*
|
|
||||||
src/jthread/Makefile
|
|
||||||
src/jthread/cmake_config.h
|
|
||||||
src/jthread/cmake_install.cmake
|
|
||||||
src/jthread/libjthread.a
|
|
||||||
src/json/libjson.a
|
|
||||||
src/lua/build/
|
|
||||||
src/lua/CMakeFiles/
|
|
||||||
src/cguittfont/CMakeFiles/
|
|
||||||
src/cguittfont/libcguittfont.a
|
|
||||||
src/cguittfont/cmake_install.cmake
|
|
||||||
src/cguittfont/Makefile
|
|
||||||
src/gmp/CMakeFiles/
|
|
||||||
src/gmp/libgmp.a
|
|
||||||
src/json/CMakeFiles/
|
|
||||||
src/json/libjsoncpp.a
|
|
||||||
src/sqlite/CMakeFiles/*
|
|
||||||
src/sqlite/libsqlite3.a
|
|
||||||
src/client/CMakeFiles/
|
|
||||||
src/network/CMakeFiles/
|
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CPackConfig.cmake
|
CPackConfig.cmake
|
||||||
CPackSourceConfig.cmake
|
CPackSourceConfig.cmake
|
||||||
Makefile
|
src/android_version.h
|
||||||
cmake_install.cmake
|
src/android_version_githash.h
|
||||||
|
src/cmake_config.h
|
||||||
|
src/cmake_config_githash.h
|
||||||
|
src/lua/build/
|
||||||
locale/
|
locale/
|
||||||
.directory
|
.directory
|
||||||
.kdev4/
|
.kdev4/
|
||||||
@ -82,6 +55,7 @@ locale/
|
|||||||
*.kdev4
|
*.kdev4
|
||||||
*.layout
|
*.layout
|
||||||
*.o
|
*.o
|
||||||
|
*.a
|
||||||
|
|
||||||
## Android build files
|
## Android build files
|
||||||
build/android/assets
|
build/android/assets
|
||||||
|
@ -342,17 +342,16 @@ LOCAL_SRC_FILES += \
|
|||||||
jni/src/lua/src/lzio.c \
|
jni/src/lua/src/lzio.c \
|
||||||
jni/src/lua/src/print.c
|
jni/src/lua/src/print.c
|
||||||
|
|
||||||
# sqlite
|
# SQLite3
|
||||||
LOCAL_SRC_FILES += deps/sqlite/sqlite3.c
|
LOCAL_SRC_FILES += deps/sqlite/sqlite3.c
|
||||||
|
|
||||||
# jthread
|
# Threading
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
jni/src/jthread/pthread/jevent.cpp \
|
jni/src/threading/Mutex.cpp \
|
||||||
jni/src/jthread/pthread/jmutex.cpp \
|
jni/src/threading/Semaphore.cpp \
|
||||||
jni/src/jthread/pthread/jsemaphore.cpp \
|
jni/src/threading/Thread.cpp
|
||||||
jni/src/jthread/pthread/jthread.cpp
|
|
||||||
|
|
||||||
# json
|
# JSONCPP
|
||||||
LOCAL_SRC_FILES += jni/src/json/jsoncpp.cpp
|
LOCAL_SRC_FILES += jni/src/json/jsoncpp.cpp
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis gmp
|
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis gmp
|
||||||
|
@ -297,7 +297,7 @@ add_custom_target(GenerateVersion
|
|||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(jthread)
|
add_subdirectory(threading)
|
||||||
add_subdirectory(network)
|
add_subdirectory(network)
|
||||||
add_subdirectory(script)
|
add_subdirectory(script)
|
||||||
add_subdirectory(unittest)
|
add_subdirectory(unittest)
|
||||||
|
18
src/ban.cpp
18
src/ban.cpp
@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "ban.h"
|
#include "ban.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "strfnd.h"
|
#include "strfnd.h"
|
||||||
@ -48,7 +48,7 @@ BanManager::~BanManager()
|
|||||||
|
|
||||||
void BanManager::load()
|
void BanManager::load()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
infostream<<"BanManager: loading from "<<m_banfilepath<<std::endl;
|
infostream<<"BanManager: loading from "<<m_banfilepath<<std::endl;
|
||||||
std::ifstream is(m_banfilepath.c_str(), std::ios::binary);
|
std::ifstream is(m_banfilepath.c_str(), std::ios::binary);
|
||||||
if(is.good() == false)
|
if(is.good() == false)
|
||||||
@ -73,7 +73,7 @@ void BanManager::load()
|
|||||||
|
|
||||||
void BanManager::save()
|
void BanManager::save()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
infostream << "BanManager: saving to " << m_banfilepath << std::endl;
|
infostream << "BanManager: saving to " << m_banfilepath << std::endl;
|
||||||
std::ostringstream ss(std::ios_base::binary);
|
std::ostringstream ss(std::ios_base::binary);
|
||||||
|
|
||||||
@ -90,13 +90,13 @@ void BanManager::save()
|
|||||||
|
|
||||||
bool BanManager::isIpBanned(const std::string &ip)
|
bool BanManager::isIpBanned(const std::string &ip)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
return m_ips.find(ip) != m_ips.end();
|
return m_ips.find(ip) != m_ips.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BanManager::getBanDescription(const std::string &ip_or_name)
|
std::string BanManager::getBanDescription(const std::string &ip_or_name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
std::string s = "";
|
std::string s = "";
|
||||||
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end(); ++it) {
|
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end(); ++it) {
|
||||||
if (it->first == ip_or_name || it->second == ip_or_name
|
if (it->first == ip_or_name || it->second == ip_or_name
|
||||||
@ -110,7 +110,7 @@ std::string BanManager::getBanDescription(const std::string &ip_or_name)
|
|||||||
|
|
||||||
std::string BanManager::getBanName(const std::string &ip)
|
std::string BanManager::getBanName(const std::string &ip)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
StringMap::iterator it = m_ips.find(ip);
|
StringMap::iterator it = m_ips.find(ip);
|
||||||
if (it == m_ips.end())
|
if (it == m_ips.end())
|
||||||
return "";
|
return "";
|
||||||
@ -119,14 +119,14 @@ std::string BanManager::getBanName(const std::string &ip)
|
|||||||
|
|
||||||
void BanManager::add(const std::string &ip, const std::string &name)
|
void BanManager::add(const std::string &ip, const std::string &name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
m_ips[ip] = name;
|
m_ips[ip] = name;
|
||||||
m_modified = true;
|
m_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BanManager::remove(const std::string &ip_or_name)
|
void BanManager::remove(const std::string &ip_or_name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end();) {
|
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end();) {
|
||||||
if ((it->first == ip_or_name) || (it->second == ip_or_name)) {
|
if ((it->first == ip_or_name) || (it->second == ip_or_name)) {
|
||||||
m_ips.erase(it++);
|
m_ips.erase(it++);
|
||||||
@ -140,7 +140,7 @@ void BanManager::remove(const std::string &ip_or_name)
|
|||||||
|
|
||||||
bool BanManager::isModified()
|
bool BanManager::isModified()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
return m_modified;
|
return m_modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#define BAN_HEADER
|
#define BAN_HEADER
|
||||||
|
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "jthread/jthread.h"
|
#include "threading/thread.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class BanManager
|
class BanManager
|
||||||
{
|
{
|
||||||
@ -40,7 +42,7 @@ public:
|
|||||||
void remove(const std::string &ip_or_name);
|
void remove(const std::string &ip_or_name);
|
||||||
bool isModified();
|
bool isModified();
|
||||||
private:
|
private:
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
std::string m_banfilepath;
|
std::string m_banfilepath;
|
||||||
StringMap m_ips;
|
StringMap m_ips;
|
||||||
bool m_modified;
|
bool m_modified;
|
||||||
|
@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <IFileSystem.h>
|
#include <IFileSystem.h>
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "util/auth.h"
|
#include "util/auth.h"
|
||||||
#include "util/directiontables.h"
|
#include "util/directiontables.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
@ -82,7 +82,7 @@ MeshUpdateQueue::MeshUpdateQueue()
|
|||||||
|
|
||||||
MeshUpdateQueue::~MeshUpdateQueue()
|
MeshUpdateQueue::~MeshUpdateQueue()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
for(std::vector<QueuedMeshUpdate*>::iterator
|
for(std::vector<QueuedMeshUpdate*>::iterator
|
||||||
i = m_queue.begin();
|
i = m_queue.begin();
|
||||||
@ -102,7 +102,7 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se
|
|||||||
|
|
||||||
assert(data); // pre-condition
|
assert(data); // pre-condition
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
if(urgent)
|
if(urgent)
|
||||||
m_urgents.insert(p);
|
m_urgents.insert(p);
|
||||||
@ -141,7 +141,7 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se
|
|||||||
// Returns NULL if queue is empty
|
// Returns NULL if queue is empty
|
||||||
QueuedMeshUpdate *MeshUpdateQueue::pop()
|
QueuedMeshUpdate *MeshUpdateQueue::pop()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
bool must_be_urgent = !m_urgents.empty();
|
bool must_be_urgent = !m_urgents.empty();
|
||||||
for(std::vector<QueuedMeshUpdate*>::iterator
|
for(std::vector<QueuedMeshUpdate*>::iterator
|
||||||
@ -269,7 +269,7 @@ Client::Client(
|
|||||||
void Client::Stop()
|
void Client::Stop()
|
||||||
{
|
{
|
||||||
//request all client managed threads to stop
|
//request all client managed threads to stop
|
||||||
m_mesh_update_thread.Stop();
|
m_mesh_update_thread.stop();
|
||||||
// Save local server map
|
// Save local server map
|
||||||
if (m_localdb) {
|
if (m_localdb) {
|
||||||
infostream << "Local map saving ended." << std::endl;
|
infostream << "Local map saving ended." << std::endl;
|
||||||
@ -280,7 +280,7 @@ void Client::Stop()
|
|||||||
bool Client::isShutdown()
|
bool Client::isShutdown()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!m_mesh_update_thread.IsRunning()) return true;
|
if (!m_mesh_update_thread.isRunning()) return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -289,8 +289,8 @@ Client::~Client()
|
|||||||
{
|
{
|
||||||
m_con.Disconnect();
|
m_con.Disconnect();
|
||||||
|
|
||||||
m_mesh_update_thread.Stop();
|
m_mesh_update_thread.stop();
|
||||||
m_mesh_update_thread.Wait();
|
m_mesh_update_thread.wait();
|
||||||
while (!m_mesh_update_thread.m_queue_out.empty()) {
|
while (!m_mesh_update_thread.m_queue_out.empty()) {
|
||||||
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
|
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
|
||||||
delete r.mesh;
|
delete r.mesh;
|
||||||
@ -1270,7 +1270,7 @@ void Client::sendPlayerPos()
|
|||||||
|
|
||||||
u16 our_peer_id;
|
u16 our_peer_id;
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
//MutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||||
our_peer_id = m_con.GetPeerID();
|
our_peer_id = m_con.GetPeerID();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1794,7 +1794,7 @@ void Client::afterContentReceived(IrrlichtDevice *device)
|
|||||||
|
|
||||||
// Start mesh update thread after setting up content definitions
|
// Start mesh update thread after setting up content definitions
|
||||||
infostream<<"- Starting mesh update thread"<<std::endl;
|
infostream<<"- Starting mesh update thread"<<std::endl;
|
||||||
m_mesh_update_thread.Start();
|
m_mesh_update_thread.start();
|
||||||
|
|
||||||
m_state = LC_Ready;
|
m_state = LC_Ready;
|
||||||
sendReady();
|
sendReady();
|
||||||
|
13
src/client.h
13
src/client.h
@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "network/connection.h"
|
#include "network/connection.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -89,14 +89,14 @@ public:
|
|||||||
|
|
||||||
u32 size()
|
u32 size()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
return m_queue.size();
|
return m_queue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<QueuedMeshUpdate*> m_queue;
|
std::vector<QueuedMeshUpdate*> m_queue;
|
||||||
std::set<v3s16> m_urgents;
|
std::set<v3s16> m_urgents;
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MeshUpdateResult
|
struct MeshUpdateResult
|
||||||
@ -119,19 +119,14 @@ private:
|
|||||||
MeshUpdateQueue m_queue_in;
|
MeshUpdateQueue m_queue_in;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const char *getName()
|
|
||||||
{ return "MeshUpdateThread"; }
|
|
||||||
virtual void doUpdate();
|
virtual void doUpdate();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MeshUpdateThread()
|
MeshUpdateThread() : UpdateThread("Mesh") {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void enqueueUpdate(v3s16 p, MeshMakeData *data,
|
void enqueueUpdate(v3s16 p, MeshMakeData *data,
|
||||||
bool ack_block_to_server, bool urgent);
|
bool ack_block_to_server, bool urgent);
|
||||||
|
|
||||||
MutexedQueue<MeshUpdateResult> m_queue_out;
|
MutexedQueue<MeshUpdateResult> m_queue_out;
|
||||||
|
|
||||||
v3s16 m_camera_offset;
|
v3s16 m_camera_offset;
|
||||||
|
@ -651,14 +651,14 @@ void ClientLauncher::speed_tests()
|
|||||||
infostream << "Around 5000/ms should do well here." << std::endl;
|
infostream << "Around 5000/ms should do well here." << std::endl;
|
||||||
TimeTaker timer("Testing mutex speed");
|
TimeTaker timer("Testing mutex speed");
|
||||||
|
|
||||||
JMutex m;
|
Mutex m;
|
||||||
u32 n = 0;
|
u32 n = 0;
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
do {
|
do {
|
||||||
n += 10000;
|
n += 10000;
|
||||||
for (; i < n; i++) {
|
for (; i < n; i++) {
|
||||||
m.Lock();
|
m.lock();
|
||||||
m.Unlock();
|
m.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Do at least 10ms
|
// Do at least 10ms
|
||||||
|
@ -414,7 +414,7 @@ private:
|
|||||||
// Maps a texture name to an index in the former.
|
// Maps a texture name to an index in the former.
|
||||||
std::map<std::string, u32> m_name_to_id;
|
std::map<std::string, u32> m_name_to_id;
|
||||||
// The two former containers are behind this mutex
|
// The two former containers are behind this mutex
|
||||||
JMutex m_textureinfo_cache_mutex;
|
Mutex m_textureinfo_cache_mutex;
|
||||||
|
|
||||||
// Queued texture fetches (to be processed by the main thread)
|
// Queued texture fetches (to be processed by the main thread)
|
||||||
RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
|
RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
|
||||||
@ -490,7 +490,7 @@ u32 TextureSource::getTextureId(const std::string &name)
|
|||||||
/*
|
/*
|
||||||
See if texture already exists
|
See if texture already exists
|
||||||
*/
|
*/
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
std::map<std::string, u32>::iterator n;
|
std::map<std::string, u32>::iterator n;
|
||||||
n = m_name_to_id.find(name);
|
n = m_name_to_id.find(name);
|
||||||
if (n != m_name_to_id.end())
|
if (n != m_name_to_id.end())
|
||||||
@ -593,7 +593,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
/*
|
/*
|
||||||
See if texture already exists
|
See if texture already exists
|
||||||
*/
|
*/
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
std::map<std::string, u32>::iterator n;
|
std::map<std::string, u32>::iterator n;
|
||||||
n = m_name_to_id.find(name);
|
n = m_name_to_id.find(name);
|
||||||
if (n != m_name_to_id.end()) {
|
if (n != m_name_to_id.end()) {
|
||||||
@ -631,7 +631,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
Add texture to caches (add NULL textures too)
|
Add texture to caches (add NULL textures too)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
u32 id = m_textureinfo_cache.size();
|
u32 id = m_textureinfo_cache.size();
|
||||||
TextureInfo ti(name, tex);
|
TextureInfo ti(name, tex);
|
||||||
@ -643,7 +643,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
|
|
||||||
std::string TextureSource::getTextureName(u32 id)
|
std::string TextureSource::getTextureName(u32 id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
if (id >= m_textureinfo_cache.size())
|
if (id >= m_textureinfo_cache.size())
|
||||||
{
|
{
|
||||||
@ -658,7 +658,7 @@ std::string TextureSource::getTextureName(u32 id)
|
|||||||
|
|
||||||
video::ITexture* TextureSource::getTexture(u32 id)
|
video::ITexture* TextureSource::getTexture(u32 id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
if (id >= m_textureinfo_cache.size())
|
if (id >= m_textureinfo_cache.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -712,7 +712,7 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
|
|||||||
|
|
||||||
void TextureSource::rebuildImagesAndTextures()
|
void TextureSource::rebuildImagesAndTextures()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||||
sanity_check(driver);
|
sanity_check(driver);
|
||||||
|
@ -593,7 +593,7 @@ ClientInterface::~ClientInterface()
|
|||||||
Delete clients
|
Delete clients
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
|
||||||
for(std::map<u16, RemoteClient*>::iterator
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
i = m_clients.begin();
|
i = m_clients.begin();
|
||||||
@ -609,7 +609,7 @@ ClientInterface::~ClientInterface()
|
|||||||
std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
|
std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
|
||||||
{
|
{
|
||||||
std::vector<u16> reply;
|
std::vector<u16> reply;
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
|
||||||
for(std::map<u16, RemoteClient*>::iterator
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
i = m_clients.begin();
|
i = m_clients.begin();
|
||||||
@ -660,7 +660,7 @@ void ClientInterface::UpdatePlayerList()
|
|||||||
infostream << "* " << player->getName() << "\t";
|
infostream << "* " << player->getName() << "\t";
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
RemoteClient* client = lockedGetClientNoEx(*i);
|
RemoteClient* client = lockedGetClientNoEx(*i);
|
||||||
if(client != NULL)
|
if(client != NULL)
|
||||||
client->PrintInfo(infostream);
|
client->PrintInfo(infostream);
|
||||||
@ -680,7 +680,7 @@ void ClientInterface::send(u16 peer_id, u8 channelnum,
|
|||||||
void ClientInterface::sendToAll(u16 channelnum,
|
void ClientInterface::sendToAll(u16 channelnum,
|
||||||
NetworkPacket* pkt, bool reliable)
|
NetworkPacket* pkt, bool reliable)
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
for(std::map<u16, RemoteClient*>::iterator
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
i = m_clients.begin();
|
i = m_clients.begin();
|
||||||
i != m_clients.end(); ++i) {
|
i != m_clients.end(); ++i) {
|
||||||
@ -694,7 +694,7 @@ void ClientInterface::sendToAll(u16 channelnum,
|
|||||||
|
|
||||||
RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
|
RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
n = m_clients.find(peer_id);
|
n = m_clients.find(peer_id);
|
||||||
// The client may not exist; clients are immediately removed if their
|
// The client may not exist; clients are immediately removed if their
|
||||||
@ -725,7 +725,7 @@ RemoteClient* ClientInterface::lockedGetClientNoEx(u16 peer_id, ClientState stat
|
|||||||
|
|
||||||
ClientState ClientInterface::getClientState(u16 peer_id)
|
ClientState ClientInterface::getClientState(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
n = m_clients.find(peer_id);
|
n = m_clients.find(peer_id);
|
||||||
// The client may not exist; clients are immediately removed if their
|
// The client may not exist; clients are immediately removed if their
|
||||||
@ -738,7 +738,7 @@ ClientState ClientInterface::getClientState(u16 peer_id)
|
|||||||
|
|
||||||
void ClientInterface::setPlayerName(u16 peer_id,std::string name)
|
void ClientInterface::setPlayerName(u16 peer_id,std::string name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientslock(m_clients_mutex);
|
MutexAutoLock clientslock(m_clients_mutex);
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
n = m_clients.find(peer_id);
|
n = m_clients.find(peer_id);
|
||||||
// The client may not exist; clients are immediately removed if their
|
// The client may not exist; clients are immediately removed if their
|
||||||
@ -749,7 +749,7 @@ void ClientInterface::setPlayerName(u16 peer_id,std::string name)
|
|||||||
|
|
||||||
void ClientInterface::DeleteClient(u16 peer_id)
|
void ClientInterface::DeleteClient(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock conlock(m_clients_mutex);
|
MutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
// Error check
|
// Error check
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
@ -784,7 +784,7 @@ void ClientInterface::DeleteClient(u16 peer_id)
|
|||||||
|
|
||||||
void ClientInterface::CreateClient(u16 peer_id)
|
void ClientInterface::CreateClient(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock conlock(m_clients_mutex);
|
MutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
// Error check
|
// Error check
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
@ -801,7 +801,7 @@ void ClientInterface::CreateClient(u16 peer_id)
|
|||||||
void ClientInterface::event(u16 peer_id, ClientStateEvent event)
|
void ClientInterface::event(u16 peer_id, ClientStateEvent event)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
JMutexAutoLock clientlock(m_clients_mutex);
|
MutexAutoLock clientlock(m_clients_mutex);
|
||||||
|
|
||||||
// Error check
|
// Error check
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
@ -823,7 +823,7 @@ void ClientInterface::event(u16 peer_id, ClientStateEvent event)
|
|||||||
|
|
||||||
u16 ClientInterface::getProtocolVersion(u16 peer_id)
|
u16 ClientInterface::getProtocolVersion(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock conlock(m_clients_mutex);
|
MutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
// Error check
|
// Error check
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
@ -838,7 +838,7 @@ u16 ClientInterface::getProtocolVersion(u16 peer_id)
|
|||||||
|
|
||||||
void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
|
void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
|
||||||
{
|
{
|
||||||
JMutexAutoLock conlock(m_clients_mutex);
|
MutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
// Error check
|
// Error check
|
||||||
std::map<u16, RemoteClient*>::iterator n;
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "serialization.h" // for SER_FMT_VER_INVALID
|
#include "serialization.h" // for SER_FMT_VER_INVALID
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "network/networkpacket.h"
|
#include "network/networkpacket.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -487,10 +487,8 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
//TODO find way to avoid this functions
|
//TODO find way to avoid this functions
|
||||||
void Lock()
|
void lock() { m_clients_mutex.lock(); }
|
||||||
{ m_clients_mutex.Lock(); }
|
void unlock() { m_clients_mutex.unlock(); }
|
||||||
void Unlock()
|
|
||||||
{ m_clients_mutex.Unlock(); }
|
|
||||||
|
|
||||||
std::map<u16, RemoteClient*>& getClientList()
|
std::map<u16, RemoteClient*>& getClientList()
|
||||||
{ return m_clients; }
|
{ return m_clients; }
|
||||||
@ -501,14 +499,14 @@ private:
|
|||||||
|
|
||||||
// Connection
|
// Connection
|
||||||
con::Connection* m_con;
|
con::Connection* m_con;
|
||||||
JMutex m_clients_mutex;
|
Mutex m_clients_mutex;
|
||||||
// Connected clients (behind the con mutex)
|
// Connected clients (behind the con mutex)
|
||||||
std::map<u16, RemoteClient*> m_clients;
|
std::map<u16, RemoteClient*> m_clients;
|
||||||
std::vector<std::string> m_clients_names; //for announcing masterserver
|
std::vector<std::string> m_clients_names; //for announcing masterserver
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
ServerEnvironment *m_env;
|
ServerEnvironment *m_env;
|
||||||
JMutex m_env_mutex;
|
Mutex m_env_mutex;
|
||||||
|
|
||||||
float m_print_info_timer;
|
float m_print_info_timer;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ ClientMap::ClientMap(
|
|||||||
|
|
||||||
ClientMap::~ClientMap()
|
ClientMap::~ClientMap()
|
||||||
{
|
{
|
||||||
/*JMutexAutoLock lock(mesh_mutex);
|
/*MutexAutoLock lock(mesh_mutex);
|
||||||
|
|
||||||
if(mesh != NULL)
|
if(mesh != NULL)
|
||||||
{
|
{
|
||||||
@ -94,7 +94,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
|
|||||||
ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
|
ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
|
||||||
|
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
//MutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||||
m_sectors[p2d] = sector;
|
m_sectors[p2d] = sector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,12 +157,12 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
|||||||
}
|
}
|
||||||
m_drawlist.clear();
|
m_drawlist.clear();
|
||||||
|
|
||||||
m_camera_mutex.Lock();
|
m_camera_mutex.lock();
|
||||||
v3f camera_position = m_camera_position;
|
v3f camera_position = m_camera_position;
|
||||||
v3f camera_direction = m_camera_direction;
|
v3f camera_direction = m_camera_direction;
|
||||||
f32 camera_fov = m_camera_fov;
|
f32 camera_fov = m_camera_fov;
|
||||||
//v3s16 camera_offset = m_camera_offset;
|
//v3s16 camera_offset = m_camera_offset;
|
||||||
m_camera_mutex.Unlock();
|
m_camera_mutex.unlock();
|
||||||
|
|
||||||
// Use a higher fov to accomodate faster camera movements.
|
// Use a higher fov to accomodate faster camera movements.
|
||||||
// Blocks are cropped better when they are drawn.
|
// Blocks are cropped better when they are drawn.
|
||||||
@ -263,7 +263,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
|||||||
Ignore if mesh doesn't exist
|
Ignore if mesh doesn't exist
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(block->mesh_mutex);
|
//MutexAutoLock lock(block->mesh_mutex);
|
||||||
|
|
||||||
if(block->mesh == NULL){
|
if(block->mesh == NULL){
|
||||||
blocks_in_range_without_mesh++;
|
blocks_in_range_without_mesh++;
|
||||||
@ -433,11 +433,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
int crack = m_client->getCrackLevel();
|
int crack = m_client->getCrackLevel();
|
||||||
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
|
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
|
||||||
|
|
||||||
m_camera_mutex.Lock();
|
m_camera_mutex.lock();
|
||||||
v3f camera_position = m_camera_position;
|
v3f camera_position = m_camera_position;
|
||||||
v3f camera_direction = m_camera_direction;
|
v3f camera_direction = m_camera_direction;
|
||||||
f32 camera_fov = m_camera_fov;
|
f32 camera_fov = m_camera_fov;
|
||||||
m_camera_mutex.Unlock();
|
m_camera_mutex.unlock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get all blocks and draw all visible ones
|
Get all blocks and draw all visible ones
|
||||||
@ -504,7 +504,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
|
|
||||||
// Mesh animation
|
// Mesh animation
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(block->mesh_mutex);
|
//MutexAutoLock lock(block->mesh_mutex);
|
||||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||||
assert(mapBlockMesh);
|
assert(mapBlockMesh);
|
||||||
// Pretty random but this should work somewhat nicely
|
// Pretty random but this should work somewhat nicely
|
||||||
@ -534,7 +534,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
Get the meshbuffers of the block
|
Get the meshbuffers of the block
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(block->mesh_mutex);
|
//MutexAutoLock lock(block->mesh_mutex);
|
||||||
|
|
||||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||||
assert(mapBlockMesh);
|
assert(mapBlockMesh);
|
||||||
@ -799,9 +799,9 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
|
|||||||
// Sadly ISceneManager has no "post effects" render pass, in that case we
|
// Sadly ISceneManager has no "post effects" render pass, in that case we
|
||||||
// could just register for that and handle it in renderMap().
|
// could just register for that and handle it in renderMap().
|
||||||
|
|
||||||
m_camera_mutex.Lock();
|
m_camera_mutex.lock();
|
||||||
v3f camera_position = m_camera_position;
|
v3f camera_position = m_camera_position;
|
||||||
m_camera_mutex.Unlock();
|
m_camera_mutex.unlock();
|
||||||
|
|
||||||
MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
|
MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public:
|
|||||||
|
|
||||||
void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset)
|
void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_camera_mutex);
|
MutexAutoLock lock(m_camera_mutex);
|
||||||
m_camera_position = pos;
|
m_camera_position = pos;
|
||||||
m_camera_direction = dir;
|
m_camera_direction = dir;
|
||||||
m_camera_fov = fov;
|
m_camera_fov = fov;
|
||||||
@ -149,7 +149,7 @@ private:
|
|||||||
v3f m_camera_direction;
|
v3f m_camera_direction;
|
||||||
f32 m_camera_fov;
|
f32 m_camera_fov;
|
||||||
v3s16 m_camera_offset;
|
v3s16 m_camera_offset;
|
||||||
JMutex m_camera_mutex;
|
Mutex m_camera_mutex;
|
||||||
|
|
||||||
std::map<v3s16, MapBlock*> m_drawlist;
|
std::map<v3s16, MapBlock*> m_drawlist;
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -229,7 +229,7 @@ void DebugStack::print(std::ostream &os, bool everything)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<threadid_t, DebugStack*> g_debug_stacks;
|
std::map<threadid_t, DebugStack*> g_debug_stacks;
|
||||||
JMutex g_debug_stacks_mutex;
|
Mutex g_debug_stacks_mutex;
|
||||||
|
|
||||||
void debug_stacks_init()
|
void debug_stacks_init()
|
||||||
{
|
{
|
||||||
@ -237,7 +237,7 @@ void debug_stacks_init()
|
|||||||
|
|
||||||
void debug_stacks_print_to(std::ostream &os)
|
void debug_stacks_print_to(std::ostream &os)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_debug_stacks_mutex);
|
MutexAutoLock lock(g_debug_stacks_mutex);
|
||||||
|
|
||||||
os<<"Debug stacks:"<<std::endl;
|
os<<"Debug stacks:"<<std::endl;
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ void debug_stacks_print_to(std::ostream &os)
|
|||||||
|
|
||||||
void debug_stacks_print()
|
void debug_stacks_print()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_debug_stacks_mutex);
|
MutexAutoLock lock(g_debug_stacks_mutex);
|
||||||
|
|
||||||
DEBUGPRINT("Debug stacks:\n");
|
DEBUGPRINT("Debug stacks:\n");
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ DebugStacker::DebugStacker(const char *text)
|
|||||||
{
|
{
|
||||||
threadid_t threadid = get_current_thread_id();
|
threadid_t threadid = get_current_thread_id();
|
||||||
|
|
||||||
JMutexAutoLock lock(g_debug_stacks_mutex);
|
MutexAutoLock lock(g_debug_stacks_mutex);
|
||||||
|
|
||||||
std::map<threadid_t, DebugStack*>::iterator n;
|
std::map<threadid_t, DebugStack*>::iterator n;
|
||||||
n = g_debug_stacks.find(threadid);
|
n = g_debug_stacks.find(threadid);
|
||||||
@ -307,7 +307,7 @@ DebugStacker::DebugStacker(const char *text)
|
|||||||
|
|
||||||
DebugStacker::~DebugStacker()
|
DebugStacker::~DebugStacker()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_debug_stacks_mutex);
|
MutexAutoLock lock(g_debug_stacks_mutex);
|
||||||
|
|
||||||
if(m_overflowed == true)
|
if(m_overflowed == true)
|
||||||
return;
|
return;
|
||||||
|
@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "jthread/jevent.h"
|
#include "threading/event.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
@ -59,7 +59,7 @@ MapgenDesc reg_mapgens[] = {
|
|||||||
{"singlenode", new MapgenFactorySinglenode},
|
{"singlenode", new MapgenFactorySinglenode},
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmergeThread : public JThread
|
class EmergeThread : public Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Server *m_server;
|
Server *m_server;
|
||||||
@ -73,7 +73,6 @@ public:
|
|||||||
std::queue<v3s16> blockqueue;
|
std::queue<v3s16> blockqueue;
|
||||||
|
|
||||||
EmergeThread(Server *server, int ethreadid):
|
EmergeThread(Server *server, int ethreadid):
|
||||||
JThread(),
|
|
||||||
m_server(server),
|
m_server(server),
|
||||||
map(NULL),
|
map(NULL),
|
||||||
emerge(NULL),
|
emerge(NULL),
|
||||||
@ -81,9 +80,10 @@ public:
|
|||||||
enable_mapgen_debug_info(false),
|
enable_mapgen_debug_info(false),
|
||||||
id(ethreadid)
|
id(ethreadid)
|
||||||
{
|
{
|
||||||
|
name = "Emerge-" + itos(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Thread();
|
void *run();
|
||||||
bool popBlockEmerge(v3s16 *pos, u8 *flags);
|
bool popBlockEmerge(v3s16 *pos, u8 *flags);
|
||||||
bool getBlockOrStartGen(v3s16 p, MapBlock **b,
|
bool getBlockOrStartGen(v3s16 p, MapBlock **b,
|
||||||
BlockMakeData *data, bool allow_generate);
|
BlockMakeData *data, bool allow_generate);
|
||||||
@ -112,7 +112,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
|
|||||||
// some other misc thread
|
// some other misc thread
|
||||||
s16 nthreads = 0;
|
s16 nthreads = 0;
|
||||||
if (!g_settings->getS16NoEx("num_emerge_threads", nthreads))
|
if (!g_settings->getS16NoEx("num_emerge_threads", nthreads))
|
||||||
nthreads = porting::getNumberOfProcessors() - 2;
|
nthreads = Thread::getNumberOfProcessors() - 2;
|
||||||
if (nthreads < 1)
|
if (nthreads < 1)
|
||||||
nthreads = 1;
|
nthreads = 1;
|
||||||
|
|
||||||
@ -141,9 +141,9 @@ EmergeManager::~EmergeManager()
|
|||||||
{
|
{
|
||||||
for (u32 i = 0; i != emergethread.size(); i++) {
|
for (u32 i = 0; i != emergethread.size(); i++) {
|
||||||
if (threads_active) {
|
if (threads_active) {
|
||||||
emergethread[i]->Stop();
|
emergethread[i]->stop();
|
||||||
emergethread[i]->qevent.signal();
|
emergethread[i]->qevent.signal();
|
||||||
emergethread[i]->Wait();
|
emergethread[i]->wait();
|
||||||
}
|
}
|
||||||
delete emergethread[i];
|
delete emergethread[i];
|
||||||
delete mapgen[i];
|
delete mapgen[i];
|
||||||
@ -196,7 +196,7 @@ void EmergeManager::initMapgens()
|
|||||||
Mapgen *EmergeManager::getCurrentMapgen()
|
Mapgen *EmergeManager::getCurrentMapgen()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i != emergethread.size(); i++) {
|
for (u32 i = 0; i != emergethread.size(); i++) {
|
||||||
if (emergethread[i]->IsSameThread())
|
if (emergethread[i]->isSameThread())
|
||||||
return emergethread[i]->mapgen;
|
return emergethread[i]->mapgen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ void EmergeManager::startThreads()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (u32 i = 0; i != emergethread.size(); i++)
|
for (u32 i = 0; i != emergethread.size(); i++)
|
||||||
emergethread[i]->Start();
|
emergethread[i]->start();
|
||||||
|
|
||||||
threads_active = true;
|
threads_active = true;
|
||||||
}
|
}
|
||||||
@ -223,13 +223,13 @@ void EmergeManager::stopThreads()
|
|||||||
|
|
||||||
// Request thread stop in parallel
|
// Request thread stop in parallel
|
||||||
for (u32 i = 0; i != emergethread.size(); i++) {
|
for (u32 i = 0; i != emergethread.size(); i++) {
|
||||||
emergethread[i]->Stop();
|
emergethread[i]->stop();
|
||||||
emergethread[i]->qevent.signal();
|
emergethread[i]->qevent.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then do the waiting for each
|
// Then do the waiting for each
|
||||||
for (u32 i = 0; i != emergethread.size(); i++)
|
for (u32 i = 0; i != emergethread.size(); i++)
|
||||||
emergethread[i]->Wait();
|
emergethread[i]->wait();
|
||||||
|
|
||||||
threads_active = false;
|
threads_active = false;
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate
|
|||||||
flags |= BLOCK_EMERGE_ALLOWGEN;
|
flags |= BLOCK_EMERGE_ALLOWGEN;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock queuelock(queuemutex);
|
MutexAutoLock queuelock(queuemutex);
|
||||||
|
|
||||||
count = blocks_enqueued.size();
|
count = blocks_enqueued.size();
|
||||||
if (count >= qlimit_total)
|
if (count >= qlimit_total)
|
||||||
@ -360,7 +360,7 @@ MapgenSpecificParams *EmergeManager::createMapgenParams(const std::string &mgnam
|
|||||||
bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags)
|
bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags)
|
||||||
{
|
{
|
||||||
std::map<v3s16, BlockEmergeData *>::iterator iter;
|
std::map<v3s16, BlockEmergeData *>::iterator iter;
|
||||||
JMutexAutoLock queuelock(emerge->queuemutex);
|
MutexAutoLock queuelock(emerge->queuemutex);
|
||||||
|
|
||||||
if (blockqueue.empty())
|
if (blockqueue.empty())
|
||||||
return false;
|
return false;
|
||||||
@ -390,7 +390,7 @@ bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b,
|
|||||||
{
|
{
|
||||||
v2s16 p2d(p.X, p.Z);
|
v2s16 p2d(p.X, p.Z);
|
||||||
//envlock: usually takes <=1ms, sometimes 90ms or ~400ms to acquire
|
//envlock: usually takes <=1ms, sometimes 90ms or ~400ms to acquire
|
||||||
JMutexAutoLock envlock(m_server->m_env_mutex);
|
MutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
|
|
||||||
// Load sector if it isn't loaded
|
// Load sector if it isn't loaded
|
||||||
if (map->getSectorNoGenerateNoEx(p2d) == NULL)
|
if (map->getSectorNoGenerateNoEx(p2d) == NULL)
|
||||||
@ -418,10 +418,8 @@ bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *EmergeThread::Thread()
|
void *EmergeThread::run()
|
||||||
{
|
{
|
||||||
ThreadStarted();
|
|
||||||
log_register_thread("EmergeThread" + itos(id));
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
|
|
||||||
@ -434,9 +432,7 @@ void *EmergeThread::Thread()
|
|||||||
mapgen = emerge->mapgen[id];
|
mapgen = emerge->mapgen[id];
|
||||||
enable_mapgen_debug_info = emerge->mapgen_debug_info;
|
enable_mapgen_debug_info = emerge->mapgen_debug_info;
|
||||||
|
|
||||||
porting::setThreadName("EmergeThread");
|
while (!stopRequested())
|
||||||
|
|
||||||
while (!StopRequested())
|
|
||||||
try {
|
try {
|
||||||
if (!popBlockEmerge(&p, &flags)) {
|
if (!popBlockEmerge(&p, &flags)) {
|
||||||
qevent.wait();
|
qevent.wait();
|
||||||
@ -471,7 +467,7 @@ void *EmergeThread::Thread()
|
|||||||
|
|
||||||
{
|
{
|
||||||
//envlock: usually 0ms, but can take either 30 or 400ms to acquire
|
//envlock: usually 0ms, but can take either 30 or 400ms to acquire
|
||||||
JMutexAutoLock envlock(m_server->m_env_mutex);
|
MutexAutoLock envlock(m_server->m_env_mutex);
|
||||||
ScopeProfiler sp(g_profiler, "EmergeThread: after "
|
ScopeProfiler sp(g_profiler, "EmergeThread: after "
|
||||||
"Mapgen::makeChunk (envlock)", SPT_AVG);
|
"Mapgen::makeChunk (envlock)", SPT_AVG);
|
||||||
|
|
||||||
@ -538,7 +534,7 @@ void *EmergeThread::Thread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock queuelock(emerge->queuemutex);
|
MutexAutoLock queuelock(emerge->queuemutex);
|
||||||
while (!blockqueue.empty())
|
while (!blockqueue.empty())
|
||||||
{
|
{
|
||||||
v3s16 p = blockqueue.front();
|
v3s16 p = blockqueue.front();
|
||||||
@ -555,6 +551,5 @@ void *EmergeThread::Thread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
END_DEBUG_EXCEPTION_HANDLER(errorstream)
|
END_DEBUG_EXCEPTION_HANDLER(errorstream)
|
||||||
log_deregister_thread();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public:
|
|||||||
std::set<u32> gen_notify_on_deco_ids;
|
std::set<u32> gen_notify_on_deco_ids;
|
||||||
|
|
||||||
//// Block emerge queue data structures
|
//// Block emerge queue data structures
|
||||||
JMutex queuemutex;
|
Mutex queuemutex;
|
||||||
std::map<v3s16, BlockEmergeData *> blocks_enqueued;
|
std::map<v3s16, BlockEmergeData *> blocks_enqueued;
|
||||||
std::map<u16, u16> peer_queue_count;
|
std::map<u16, u16> peer_queue_count;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "emerge.h"
|
#include "emerge.h"
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
|
|
||||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||||
|
|
||||||
@ -204,34 +204,34 @@ u32 Environment::getDayNightRatio()
|
|||||||
|
|
||||||
void Environment::setTimeOfDaySpeed(float speed)
|
void Environment::setTimeOfDaySpeed(float speed)
|
||||||
{
|
{
|
||||||
JMutexAutoLock(this->m_timeofday_lock);
|
MutexAutoLock(this->m_timeofday_lock);
|
||||||
m_time_of_day_speed = speed;
|
m_time_of_day_speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Environment::getTimeOfDaySpeed()
|
float Environment::getTimeOfDaySpeed()
|
||||||
{
|
{
|
||||||
JMutexAutoLock(this->m_timeofday_lock);
|
MutexAutoLock(this->m_timeofday_lock);
|
||||||
float retval = m_time_of_day_speed;
|
float retval = m_time_of_day_speed;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Environment::setTimeOfDay(u32 time)
|
void Environment::setTimeOfDay(u32 time)
|
||||||
{
|
{
|
||||||
JMutexAutoLock(this->m_time_lock);
|
MutexAutoLock(this->m_time_lock);
|
||||||
m_time_of_day = time;
|
m_time_of_day = time;
|
||||||
m_time_of_day_f = (float)time / 24000.0;
|
m_time_of_day_f = (float)time / 24000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Environment::getTimeOfDay()
|
u32 Environment::getTimeOfDay()
|
||||||
{
|
{
|
||||||
JMutexAutoLock(this->m_time_lock);
|
MutexAutoLock(this->m_time_lock);
|
||||||
u32 retval = m_time_of_day;
|
u32 retval = m_time_of_day;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Environment::getTimeOfDayF()
|
float Environment::getTimeOfDayF()
|
||||||
{
|
{
|
||||||
JMutexAutoLock(this->m_time_lock);
|
MutexAutoLock(this->m_time_lock);
|
||||||
float retval = m_time_of_day_f;
|
float retval = m_time_of_day_f;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "mapnode.h"
|
#include "mapnode.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "network/networkprotocol.h" // for AccessDeniedCode
|
#include "network/networkprotocol.h" // for AccessDeniedCode
|
||||||
|
|
||||||
class ServerEnvironment;
|
class ServerEnvironment;
|
||||||
@ -127,8 +127,8 @@ protected:
|
|||||||
bool m_cache_enable_shaders;
|
bool m_cache_enable_shaders;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JMutex m_timeofday_lock;
|
Mutex m_timeofday_lock;
|
||||||
JMutex m_time_lock;
|
Mutex m_time_lock;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "jthread/jevent.h"
|
#include "threading/event.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
JMutex g_httpfetch_mutex;
|
Mutex g_httpfetch_mutex;
|
||||||
std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
|
std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
|
||||||
|
|
||||||
HTTPFetchRequest::HTTPFetchRequest()
|
HTTPFetchRequest::HTTPFetchRequest()
|
||||||
@ -55,7 +55,7 @@ static void httpfetch_deliver_result(const HTTPFetchResult &fetch_result)
|
|||||||
{
|
{
|
||||||
unsigned long caller = fetch_result.caller;
|
unsigned long caller = fetch_result.caller;
|
||||||
if (caller != HTTPFETCH_DISCARD) {
|
if (caller != HTTPFETCH_DISCARD) {
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
MutexAutoLock lock(g_httpfetch_mutex);
|
||||||
g_httpfetch_results[caller].push(fetch_result);
|
g_httpfetch_results[caller].push(fetch_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ static void httpfetch_request_clear(unsigned long caller);
|
|||||||
|
|
||||||
unsigned long httpfetch_caller_alloc()
|
unsigned long httpfetch_caller_alloc()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
MutexAutoLock lock(g_httpfetch_mutex);
|
||||||
|
|
||||||
// Check each caller ID except HTTPFETCH_DISCARD
|
// Check each caller ID except HTTPFETCH_DISCARD
|
||||||
const unsigned long discard = HTTPFETCH_DISCARD;
|
const unsigned long discard = HTTPFETCH_DISCARD;
|
||||||
@ -91,14 +91,14 @@ void httpfetch_caller_free(unsigned long caller)
|
|||||||
|
|
||||||
httpfetch_request_clear(caller);
|
httpfetch_request_clear(caller);
|
||||||
if (caller != HTTPFETCH_DISCARD) {
|
if (caller != HTTPFETCH_DISCARD) {
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
MutexAutoLock lock(g_httpfetch_mutex);
|
||||||
g_httpfetch_results.erase(caller);
|
g_httpfetch_results.erase(caller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result)
|
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
MutexAutoLock lock(g_httpfetch_mutex);
|
||||||
|
|
||||||
// Check that caller exists
|
// Check that caller exists
|
||||||
std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
|
std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
|
||||||
@ -390,7 +390,7 @@ HTTPFetchOngoing::~HTTPFetchOngoing()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CurlFetchThread : public JThread
|
class CurlFetchThread : public Thread
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
enum RequestType {
|
enum RequestType {
|
||||||
@ -414,7 +414,8 @@ protected:
|
|||||||
std::list<HTTPFetchRequest> m_queued_fetches;
|
std::list<HTTPFetchRequest> m_queued_fetches;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CurlFetchThread(int parallel_limit)
|
CurlFetchThread(int parallel_limit) :
|
||||||
|
Thread("CurlFetch")
|
||||||
{
|
{
|
||||||
if (parallel_limit >= 1)
|
if (parallel_limit >= 1)
|
||||||
m_parallel_limit = parallel_limit;
|
m_parallel_limit = parallel_limit;
|
||||||
@ -613,14 +614,10 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void * Thread()
|
void *run()
|
||||||
{
|
{
|
||||||
ThreadStarted();
|
|
||||||
log_register_thread("CurlFetchThread");
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
porting::setThreadName("CurlFetchThread");
|
|
||||||
|
|
||||||
CurlHandlePool pool;
|
CurlHandlePool pool;
|
||||||
|
|
||||||
m_multi = curl_multi_init();
|
m_multi = curl_multi_init();
|
||||||
@ -631,7 +628,7 @@ protected:
|
|||||||
|
|
||||||
FATAL_ERROR_IF(!m_all_ongoing.empty(), "Expected empty");
|
FATAL_ERROR_IF(!m_all_ongoing.empty(), "Expected empty");
|
||||||
|
|
||||||
while (!StopRequested()) {
|
while (!stopRequested()) {
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -719,9 +716,9 @@ void httpfetch_cleanup()
|
|||||||
{
|
{
|
||||||
verbosestream<<"httpfetch_cleanup: cleaning up"<<std::endl;
|
verbosestream<<"httpfetch_cleanup: cleaning up"<<std::endl;
|
||||||
|
|
||||||
g_httpfetch_thread->Stop();
|
g_httpfetch_thread->stop();
|
||||||
g_httpfetch_thread->requestWakeUp();
|
g_httpfetch_thread->requestWakeUp();
|
||||||
g_httpfetch_thread->Wait();
|
g_httpfetch_thread->wait();
|
||||||
delete g_httpfetch_thread;
|
delete g_httpfetch_thread;
|
||||||
|
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
@ -730,18 +727,17 @@ void httpfetch_cleanup()
|
|||||||
void httpfetch_async(const HTTPFetchRequest &fetch_request)
|
void httpfetch_async(const HTTPFetchRequest &fetch_request)
|
||||||
{
|
{
|
||||||
g_httpfetch_thread->requestFetch(fetch_request);
|
g_httpfetch_thread->requestFetch(fetch_request);
|
||||||
if (!g_httpfetch_thread->IsRunning())
|
if (!g_httpfetch_thread->isRunning())
|
||||||
g_httpfetch_thread->Start();
|
g_httpfetch_thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void httpfetch_request_clear(unsigned long caller)
|
static void httpfetch_request_clear(unsigned long caller)
|
||||||
{
|
{
|
||||||
if (g_httpfetch_thread->IsRunning()) {
|
if (g_httpfetch_thread->isRunning()) {
|
||||||
Event event;
|
Event event;
|
||||||
g_httpfetch_thread->requestClear(caller, &event);
|
g_httpfetch_thread->requestClear(caller, &event);
|
||||||
event.wait();
|
event.wait();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
g_httpfetch_thread->requestClear(caller, NULL);
|
g_httpfetch_thread->requestClear(caller, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
if(UNIX)
|
|
||||||
set(THREAD_SYS_DIR pthread)
|
|
||||||
else()
|
|
||||||
set(THREAD_SYS_DIR win32)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(SRC_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/${THREAD_SYS_DIR})
|
|
||||||
set(JTHREAD_SRCS
|
|
||||||
${SRC_PREFIX}/jmutex.cpp
|
|
||||||
${SRC_PREFIX}/jthread.cpp
|
|
||||||
${SRC_PREFIX}/jsemaphore.cpp
|
|
||||||
${SRC_PREFIX}/jevent.cpp
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JEVENT_H_
|
|
||||||
#define JEVENT_H_
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#elif defined(__MACH__) && defined(__APPLE__)
|
|
||||||
#include <mach/mach.h>
|
|
||||||
#include <mach/task.h>
|
|
||||||
#include <mach/semaphore.h>
|
|
||||||
#include <sys/semaphore.h>
|
|
||||||
#else
|
|
||||||
#include <semaphore.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class Event {
|
|
||||||
#ifdef _WIN32
|
|
||||||
HANDLE hEvent;
|
|
||||||
#elif defined(__MACH__) && defined(__APPLE__)
|
|
||||||
semaphore_t sem;
|
|
||||||
#else
|
|
||||||
sem_t sem;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
Event();
|
|
||||||
~Event();
|
|
||||||
void wait();
|
|
||||||
void signal();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* JEVENT_H_ */
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JMUTEX_H
|
|
||||||
|
|
||||||
#define JMUTEX_H
|
|
||||||
|
|
||||||
#if (defined(WIN32) || defined(_WIN32_WCE))
|
|
||||||
#ifndef _WIN32_WINNT
|
|
||||||
#define _WIN32_WINNT 0x0501
|
|
||||||
#endif
|
|
||||||
#ifndef _WIN32_WCE
|
|
||||||
#include <process.h>
|
|
||||||
#endif // _WIN32_WCE
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
// CriticalSection is way faster than the alternative
|
|
||||||
#define JMUTEX_CRITICALSECTION
|
|
||||||
#else // using pthread
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif // WIN32
|
|
||||||
|
|
||||||
#define ERR_JMUTEX_ALREADYINIT -1
|
|
||||||
#define ERR_JMUTEX_NOTINIT -2
|
|
||||||
#define ERR_JMUTEX_CANTCREATEMUTEX -3
|
|
||||||
|
|
||||||
class JMutex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JMutex();
|
|
||||||
~JMutex();
|
|
||||||
int Lock();
|
|
||||||
int Unlock();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if (defined(WIN32) || defined(_WIN32_WCE))
|
|
||||||
#ifdef JMUTEX_CRITICALSECTION
|
|
||||||
CRITICAL_SECTION mutex;
|
|
||||||
#else // Use standard mutex
|
|
||||||
HANDLE mutex;
|
|
||||||
#endif // JMUTEX_CRITICALSECTION
|
|
||||||
#else // pthread mutex
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
|
|
||||||
bool IsLocked() {
|
|
||||||
if (pthread_mutex_trylock(&mutex)) {
|
|
||||||
pthread_mutex_unlock(&mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif // WIN32
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // JMUTEX_H
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JMUTEXAUTOLOCK_H
|
|
||||||
|
|
||||||
#define JMUTEXAUTOLOCK_H
|
|
||||||
|
|
||||||
#include "jmutex.h"
|
|
||||||
|
|
||||||
class JMutexAutoLock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JMutexAutoLock(JMutex &m) : mutex(m) { mutex.Lock(); }
|
|
||||||
~JMutexAutoLock() { mutex.Unlock(); }
|
|
||||||
private:
|
|
||||||
JMutex &mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // JMUTEXAUTOLOCK_H
|
|
@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JTHREAD_H
|
|
||||||
#define JTHREAD_H
|
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
|
||||||
#include <atomic>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "jthread/jmutex.h"
|
|
||||||
|
|
||||||
#define ERR_JTHREAD_CANTINITMUTEX -1
|
|
||||||
#define ERR_JTHREAD_CANTSTARTTHREAD -2
|
|
||||||
#define ERR_JTHREAD_THREADFUNCNOTSET -3
|
|
||||||
#define ERR_JTHREAD_NOTRUNNING -4
|
|
||||||
#define ERR_JTHREAD_ALREADYRUNNING -5
|
|
||||||
|
|
||||||
class JThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JThread();
|
|
||||||
virtual ~JThread();
|
|
||||||
int Start();
|
|
||||||
inline void Stop()
|
|
||||||
{ requeststop = true; }
|
|
||||||
int Kill();
|
|
||||||
virtual void *Thread() = 0;
|
|
||||||
inline bool IsRunning()
|
|
||||||
{ return running; }
|
|
||||||
inline bool StopRequested()
|
|
||||||
{ return requeststop; }
|
|
||||||
void *GetReturnValue();
|
|
||||||
bool IsSameThread();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait for thread to finish
|
|
||||||
* Note: this does not stop a thread you have to do this on your own
|
|
||||||
* WARNING: never ever call this on a thread not started or already killed!
|
|
||||||
*/
|
|
||||||
void Wait();
|
|
||||||
protected:
|
|
||||||
void ThreadStarted();
|
|
||||||
private:
|
|
||||||
|
|
||||||
#if (defined(WIN32) || defined(_WIN32_WCE))
|
|
||||||
#ifdef _WIN32_WCE
|
|
||||||
DWORD threadid;
|
|
||||||
static DWORD WINAPI TheThread(void *param);
|
|
||||||
#else
|
|
||||||
static UINT __stdcall TheThread(void *param);
|
|
||||||
UINT threadid;
|
|
||||||
#endif // _WIN32_WCE
|
|
||||||
HANDLE threadhandle;
|
|
||||||
#else // pthread type threads
|
|
||||||
static void *TheThread(void *param);
|
|
||||||
|
|
||||||
pthread_t threadid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reading and writing bool values is atomic on all relevant architectures
|
|
||||||
* ( x86 + arm ). No need to waste time for locking here.
|
|
||||||
* once C++11 is supported we can tell compiler to handle cpu caches correct
|
|
||||||
* too. This should cause additional improvement (and silence thread
|
|
||||||
* concurrency check tools.
|
|
||||||
*/
|
|
||||||
#if __cplusplus >= 201103L
|
|
||||||
std::atomic_bool started;
|
|
||||||
#else
|
|
||||||
bool started;
|
|
||||||
#endif
|
|
||||||
#endif // WIN32
|
|
||||||
void *retval;
|
|
||||||
/*
|
|
||||||
* reading and writing bool values is atomic on all relevant architectures
|
|
||||||
* ( x86 + arm ). No need to waste time for locking here.
|
|
||||||
* once C++11 is supported we can tell compiler to handle cpu caches correct
|
|
||||||
* too. This should cause additional improvement (and silence thread
|
|
||||||
* concurrency check tools.
|
|
||||||
*/
|
|
||||||
#if __cplusplus >= 201103L
|
|
||||||
std::atomic_bool running;
|
|
||||||
std::atomic_bool requeststop;
|
|
||||||
#else
|
|
||||||
bool running;
|
|
||||||
bool requeststop;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JMutex continuemutex,continuemutex2;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // JTHREAD_H
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include <assert.h>
|
|
||||||
#include "jthread/jevent.h"
|
|
||||||
|
|
||||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
||||||
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
#undef sem_t
|
|
||||||
#define sem_t semaphore_t
|
|
||||||
#undef sem_init
|
|
||||||
#define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
|
|
||||||
#undef sem_wait
|
|
||||||
#define sem_wait(s) semaphore_wait(*(s))
|
|
||||||
#undef sem_post
|
|
||||||
#define sem_post(s) semaphore_signal(*(s))
|
|
||||||
#undef sem_destroy
|
|
||||||
#define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Event::Event() {
|
|
||||||
int sem_init_retval = sem_init(&sem, 0, 0);
|
|
||||||
assert(sem_init_retval == 0);
|
|
||||||
UNUSED(sem_init_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::~Event() {
|
|
||||||
int sem_destroy_retval = sem_destroy(&sem);
|
|
||||||
assert(sem_destroy_retval == 0);
|
|
||||||
UNUSED(sem_destroy_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::wait() {
|
|
||||||
int sem_wait_retval = sem_wait(&sem);
|
|
||||||
assert(sem_wait_retval == 0);
|
|
||||||
UNUSED(sem_wait_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::signal() {
|
|
||||||
int sem_post_retval = sem_post(&sem);
|
|
||||||
assert(sem_post_retval == 0);
|
|
||||||
UNUSED(sem_post_retval);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include <assert.h>
|
|
||||||
#include "jthread/jmutex.h"
|
|
||||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
||||||
JMutex::JMutex()
|
|
||||||
{
|
|
||||||
int mutex_init_retval = pthread_mutex_init(&mutex,NULL);
|
|
||||||
assert( mutex_init_retval == 0 );
|
|
||||||
UNUSED(mutex_init_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
JMutex::~JMutex()
|
|
||||||
{
|
|
||||||
int mutex_dextroy_retval = pthread_mutex_destroy(&mutex);
|
|
||||||
assert( mutex_dextroy_retval == 0 );
|
|
||||||
UNUSED(mutex_dextroy_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int JMutex::Lock()
|
|
||||||
{
|
|
||||||
int mutex_lock_retval = pthread_mutex_lock(&mutex);
|
|
||||||
assert( mutex_lock_retval == 0 );
|
|
||||||
return mutex_lock_retval;
|
|
||||||
UNUSED(mutex_lock_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int JMutex::Unlock()
|
|
||||||
{
|
|
||||||
int mutex_unlock_retval = pthread_mutex_unlock(&mutex);
|
|
||||||
assert( mutex_unlock_retval == 0 );
|
|
||||||
return mutex_unlock_retval;
|
|
||||||
UNUSED(mutex_unlock_retval);
|
|
||||||
}
|
|
@ -1,156 +0,0 @@
|
|||||||
/*
|
|
||||||
Minetest
|
|
||||||
Copyright (C) 2013 sapier, < sapier AT gmx DOT net >
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include "jthread/jsemaphore.h"
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
||||||
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
#undef sem_t
|
|
||||||
#undef sem_init
|
|
||||||
#undef sem_wait
|
|
||||||
#undef sem_post
|
|
||||||
#undef sem_destroy
|
|
||||||
#define sem_t semaphore_t
|
|
||||||
#define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
|
|
||||||
#define sem_wait(s) semaphore_wait(*(s))
|
|
||||||
#define sem_post(s) semaphore_signal(*(s))
|
|
||||||
#define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
|
|
||||||
pthread_mutex_t semcount_mutex;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSemaphore::JSemaphore() {
|
|
||||||
int sem_init_retval = sem_init(&m_semaphore,0,0);
|
|
||||||
assert(sem_init_retval == 0);
|
|
||||||
UNUSED(sem_init_retval);
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
semcount = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
JSemaphore::~JSemaphore() {
|
|
||||||
int sem_destroy_retval = sem_destroy(&m_semaphore);
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
// WORKAROUND for broken bionic semaphore implementation!
|
|
||||||
assert(
|
|
||||||
(sem_destroy_retval == 0) ||
|
|
||||||
(errno == EBUSY)
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
assert(sem_destroy_retval == 0);
|
|
||||||
#endif
|
|
||||||
UNUSED(sem_destroy_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSemaphore::JSemaphore(int initval) {
|
|
||||||
int sem_init_retval = sem_init(&m_semaphore,0,initval);
|
|
||||||
assert(sem_init_retval == 0);
|
|
||||||
UNUSED(sem_init_retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JSemaphore::Post() {
|
|
||||||
int sem_post_retval = sem_post(&m_semaphore);
|
|
||||||
assert(sem_post_retval == 0);
|
|
||||||
UNUSED(sem_post_retval);
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
pthread_mutex_lock(&semcount_mutex);
|
|
||||||
semcount++;
|
|
||||||
pthread_mutex_unlock(&semcount_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void JSemaphore::Wait() {
|
|
||||||
int sem_wait_retval = sem_wait(&m_semaphore);
|
|
||||||
assert(sem_wait_retval == 0);
|
|
||||||
UNUSED(sem_wait_retval);
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
pthread_mutex_lock(&semcount_mutex);
|
|
||||||
semcount--;
|
|
||||||
pthread_mutex_unlock(&semcount_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JSemaphore::Wait(unsigned int time_ms) {
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
mach_timespec_t waittime;
|
|
||||||
waittime.tv_sec = time_ms / 1000;
|
|
||||||
waittime.tv_nsec = 1000000 * (time_ms % 1000);
|
|
||||||
#else
|
|
||||||
struct timespec waittime;
|
|
||||||
#endif
|
|
||||||
struct timeval now;
|
|
||||||
|
|
||||||
if (gettimeofday(&now, NULL) == -1) {
|
|
||||||
assert("Unable to get time by clock_gettime!" == 0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !(defined(__MACH__) && defined(__APPLE__))
|
|
||||||
waittime.tv_nsec = ((time_ms % 1000) * 1000 * 1000) + (now.tv_usec * 1000);
|
|
||||||
waittime.tv_sec = (time_ms / 1000) + (waittime.tv_nsec / (1000*1000*1000)) + now.tv_sec;
|
|
||||||
waittime.tv_nsec %= 1000*1000*1000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
int sem_wait_retval = semaphore_timedwait(m_semaphore, waittime);
|
|
||||||
if (sem_wait_retval == KERN_OPERATION_TIMED_OUT) {
|
|
||||||
errno = ETIMEDOUT;
|
|
||||||
} else if (sem_wait_retval == KERN_ABORTED) {
|
|
||||||
errno = EINTR;
|
|
||||||
} else if (sem_wait_retval != 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int sem_wait_retval = sem_timedwait(&m_semaphore, &waittime);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (sem_wait_retval == 0)
|
|
||||||
{
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
pthread_mutex_lock(&semcount_mutex);
|
|
||||||
semcount--;
|
|
||||||
pthread_mutex_unlock(&semcount_mutex);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert((errno == ETIMEDOUT) || (errno == EINTR));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return sem_wait_retval == 0 ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JSemaphore::GetValue() {
|
|
||||||
int retval = 0;
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
|
||||||
pthread_mutex_lock(&semcount_mutex);
|
|
||||||
retval = semcount;
|
|
||||||
pthread_mutex_unlock(&semcount_mutex);
|
|
||||||
#else
|
|
||||||
sem_getvalue(&m_semaphore, &retval);
|
|
||||||
#endif
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "jthread/jthread.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
||||||
|
|
||||||
JThread::JThread()
|
|
||||||
{
|
|
||||||
retval = NULL;
|
|
||||||
requeststop = false;
|
|
||||||
running = false;
|
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JThread::~JThread()
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JThread::Wait() {
|
|
||||||
void* status;
|
|
||||||
if (started) {
|
|
||||||
int pthread_join_retval = pthread_join(threadid,&status);
|
|
||||||
assert(pthread_join_retval == 0);
|
|
||||||
UNUSED(pthread_join_retval);
|
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int JThread::Start()
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (running)
|
|
||||||
{
|
|
||||||
return ERR_JTHREAD_ALREADYRUNNING;
|
|
||||||
}
|
|
||||||
requeststop = false;
|
|
||||||
|
|
||||||
pthread_attr_t attr;
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
//pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
|
||||||
|
|
||||||
continuemutex.Lock();
|
|
||||||
status = pthread_create(&threadid,&attr,TheThread,this);
|
|
||||||
pthread_attr_destroy(&attr);
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
continuemutex.Unlock();
|
|
||||||
return ERR_JTHREAD_CANTSTARTTHREAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until 'running' is set */
|
|
||||||
|
|
||||||
while (!running)
|
|
||||||
{
|
|
||||||
struct timespec req,rem;
|
|
||||||
|
|
||||||
req.tv_sec = 0;
|
|
||||||
req.tv_nsec = 1000000;
|
|
||||||
nanosleep(&req,&rem);
|
|
||||||
}
|
|
||||||
started = true;
|
|
||||||
|
|
||||||
continuemutex.Unlock();
|
|
||||||
|
|
||||||
continuemutex2.Lock();
|
|
||||||
continuemutex2.Unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JThread::Kill()
|
|
||||||
{
|
|
||||||
void* status;
|
|
||||||
if (!running)
|
|
||||||
{
|
|
||||||
if (started) {
|
|
||||||
int pthread_join_retval = pthread_join(threadid,&status);
|
|
||||||
assert(pthread_join_retval == 0);
|
|
||||||
UNUSED(pthread_join_retval);
|
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
return ERR_JTHREAD_NOTRUNNING;
|
|
||||||
}
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
pthread_kill(threadid, SIGKILL);
|
|
||||||
#else
|
|
||||||
pthread_cancel(threadid);
|
|
||||||
#endif
|
|
||||||
if (started) {
|
|
||||||
int pthread_join_retval = pthread_join(threadid,&status);
|
|
||||||
assert(pthread_join_retval == 0);
|
|
||||||
UNUSED(pthread_join_retval);
|
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
running = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *JThread::GetReturnValue()
|
|
||||||
{
|
|
||||||
void *val;
|
|
||||||
|
|
||||||
if (running) {
|
|
||||||
val = NULL;
|
|
||||||
} else {
|
|
||||||
val = retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JThread::IsSameThread()
|
|
||||||
{
|
|
||||||
return pthread_equal(pthread_self(), threadid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *JThread::TheThread(void *param)
|
|
||||||
{
|
|
||||||
JThread *jthread = (JThread *)param;
|
|
||||||
|
|
||||||
jthread->continuemutex2.Lock();
|
|
||||||
jthread->running = true;
|
|
||||||
|
|
||||||
jthread->continuemutex.Lock();
|
|
||||||
jthread->continuemutex.Unlock();
|
|
||||||
|
|
||||||
jthread->Thread();
|
|
||||||
|
|
||||||
jthread->running = false;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JThread::ThreadStarted()
|
|
||||||
{
|
|
||||||
continuemutex2.Unlock();
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include "jthread/jevent.h"
|
|
||||||
|
|
||||||
Event::Event() {
|
|
||||||
hEvent = CreateEvent(NULL, 0, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::~Event() {
|
|
||||||
CloseHandle(hEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::wait() {
|
|
||||||
WaitForSingleObject(hEvent, INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::signal() {
|
|
||||||
SetEvent(hEvent);
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include <assert.h>
|
|
||||||
#include "jthread/jmutex.h"
|
|
||||||
|
|
||||||
JMutex::JMutex()
|
|
||||||
{
|
|
||||||
#ifdef JMUTEX_CRITICALSECTION
|
|
||||||
InitializeCriticalSection(&mutex);
|
|
||||||
#else
|
|
||||||
mutex = CreateMutex(NULL,FALSE,NULL);
|
|
||||||
assert(mutex != NULL);
|
|
||||||
#endif // JMUTEX_CRITICALSECTION
|
|
||||||
}
|
|
||||||
|
|
||||||
JMutex::~JMutex()
|
|
||||||
{
|
|
||||||
#ifdef JMUTEX_CRITICALSECTION
|
|
||||||
DeleteCriticalSection(&mutex);
|
|
||||||
#else
|
|
||||||
CloseHandle(mutex);
|
|
||||||
#endif // JMUTEX_CRITICALSECTION
|
|
||||||
}
|
|
||||||
|
|
||||||
int JMutex::Lock()
|
|
||||||
{
|
|
||||||
#ifdef JMUTEX_CRITICALSECTION
|
|
||||||
EnterCriticalSection(&mutex);
|
|
||||||
#else
|
|
||||||
WaitForSingleObject(mutex,INFINITE);
|
|
||||||
#endif // JMUTEX_CRITICALSECTION
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JMutex::Unlock()
|
|
||||||
{
|
|
||||||
#ifdef JMUTEX_CRITICALSECTION
|
|
||||||
LeaveCriticalSection(&mutex);
|
|
||||||
#else
|
|
||||||
ReleaseMutex(mutex);
|
|
||||||
#endif // JMUTEX_CRITICALSECTION
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
Minetest
|
|
||||||
Copyright (C) 2013 sapier, < sapier AT gmx DOT net >
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
#include "jthread/jsemaphore.h"
|
|
||||||
|
|
||||||
JSemaphore::JSemaphore() {
|
|
||||||
m_hSemaphore = CreateSemaphore(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
MAX_SEMAPHORE_COUNT,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSemaphore::~JSemaphore() {
|
|
||||||
CloseHandle(m_hSemaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSemaphore::JSemaphore(int initval) {
|
|
||||||
m_hSemaphore = CreateSemaphore(
|
|
||||||
0,
|
|
||||||
initval,
|
|
||||||
MAX_SEMAPHORE_COUNT,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JSemaphore::Post() {
|
|
||||||
ReleaseSemaphore(
|
|
||||||
m_hSemaphore,
|
|
||||||
1,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JSemaphore::Wait() {
|
|
||||||
WaitForSingleObject(
|
|
||||||
m_hSemaphore,
|
|
||||||
INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JSemaphore::Wait(unsigned int time_ms) {
|
|
||||||
unsigned int retval = WaitForSingleObject(
|
|
||||||
m_hSemaphore,
|
|
||||||
time_ms);
|
|
||||||
|
|
||||||
if (retval == WAIT_OBJECT_0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(retval == WAIT_TIMEOUT);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef LONG (NTAPI *_NtQuerySemaphore)(
|
|
||||||
HANDLE SemaphoreHandle,
|
|
||||||
DWORD SemaphoreInformationClass,
|
|
||||||
PVOID SemaphoreInformation,
|
|
||||||
ULONG SemaphoreInformationLength,
|
|
||||||
PULONG ReturnLength OPTIONAL
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef struct _SEMAPHORE_BASIC_INFORMATION {
|
|
||||||
ULONG CurrentCount;
|
|
||||||
ULONG MaximumCount;
|
|
||||||
} SEMAPHORE_BASIC_INFORMATION;
|
|
||||||
|
|
||||||
/* Note: this will only work as long as jthread is directly linked to application */
|
|
||||||
/* it's gonna fail if someone tries to build jthread as dll */
|
|
||||||
static _NtQuerySemaphore NtQuerySemaphore =
|
|
||||||
(_NtQuerySemaphore)
|
|
||||||
GetProcAddress
|
|
||||||
(GetModuleHandle ("ntdll.dll"), "NtQuerySemaphore");
|
|
||||||
|
|
||||||
int JSemaphore::GetValue() {
|
|
||||||
SEMAPHORE_BASIC_INFORMATION BasicInfo;
|
|
||||||
LONG retval;
|
|
||||||
|
|
||||||
assert(NtQuerySemaphore);
|
|
||||||
|
|
||||||
retval = NtQuerySemaphore (m_hSemaphore, 0,
|
|
||||||
&BasicInfo, sizeof (SEMAPHORE_BASIC_INFORMATION), NULL);
|
|
||||||
|
|
||||||
if (retval == ERROR_SUCCESS)
|
|
||||||
return BasicInfo.CurrentCount;
|
|
||||||
|
|
||||||
assert("unable to read semaphore count" == 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This file is a part of the JThread package, which contains some object-
|
|
||||||
oriented thread wrappers for different thread implementations.
|
|
||||||
|
|
||||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "jthread/jthread.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
||||||
#ifndef _WIN32_WCE
|
|
||||||
#include <process.h>
|
|
||||||
#endif // _WIN32_WCE
|
|
||||||
|
|
||||||
JThread::JThread()
|
|
||||||
{
|
|
||||||
retval = NULL;
|
|
||||||
requeststop = false;
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JThread::~JThread()
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JThread::Wait() {
|
|
||||||
if (running)
|
|
||||||
{
|
|
||||||
WaitForSingleObject(threadhandle, INFINITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int JThread::Start()
|
|
||||||
{
|
|
||||||
if (running)
|
|
||||||
{
|
|
||||||
return ERR_JTHREAD_ALREADYRUNNING;
|
|
||||||
}
|
|
||||||
requeststop = false;
|
|
||||||
|
|
||||||
continuemutex.Lock();
|
|
||||||
#ifndef _WIN32_WCE
|
|
||||||
threadhandle = (HANDLE)_beginthreadex(NULL,0,TheThread,this,0,&threadid);
|
|
||||||
#else
|
|
||||||
threadhandle = CreateThread(NULL,0,TheThread,this,0,&threadid);
|
|
||||||
#endif // _WIN32_WCE
|
|
||||||
if (threadhandle == NULL)
|
|
||||||
{
|
|
||||||
continuemutex.Unlock();
|
|
||||||
return ERR_JTHREAD_CANTSTARTTHREAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until 'running' is set */
|
|
||||||
while (!running)
|
|
||||||
{
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
continuemutex.Unlock();
|
|
||||||
|
|
||||||
continuemutex2.Lock();
|
|
||||||
continuemutex2.Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JThread::Kill()
|
|
||||||
{
|
|
||||||
if (!running)
|
|
||||||
{
|
|
||||||
return ERR_JTHREAD_NOTRUNNING;
|
|
||||||
}
|
|
||||||
TerminateThread(threadhandle,0);
|
|
||||||
CloseHandle(threadhandle);
|
|
||||||
running = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *JThread::GetReturnValue()
|
|
||||||
{
|
|
||||||
void *val;
|
|
||||||
|
|
||||||
if (running) {
|
|
||||||
val = NULL;
|
|
||||||
} else {
|
|
||||||
val = retval;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JThread::IsSameThread()
|
|
||||||
{
|
|
||||||
return GetCurrentThreadId() == threadid;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32_WCE
|
|
||||||
UINT __stdcall JThread::TheThread(void *param)
|
|
||||||
#else
|
|
||||||
DWORD WINAPI JThread::TheThread(void *param)
|
|
||||||
#endif // _WIN32_WCE
|
|
||||||
{
|
|
||||||
JThread *jthread;
|
|
||||||
void *ret;
|
|
||||||
|
|
||||||
jthread = (JThread *)param;
|
|
||||||
|
|
||||||
jthread->continuemutex2.Lock();
|
|
||||||
jthread->running = true;
|
|
||||||
|
|
||||||
jthread->continuemutex.Lock();
|
|
||||||
jthread->continuemutex.Unlock();
|
|
||||||
|
|
||||||
ret = jthread->Thread();
|
|
||||||
|
|
||||||
jthread->running = false;
|
|
||||||
jthread->retval = ret;
|
|
||||||
CloseHandle(jthread->threadhandle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JThread::ThreadStarted()
|
|
||||||
{
|
|
||||||
continuemutex2.Unlock();
|
|
||||||
}
|
|
||||||
|
|
22
src/log.cpp
22
src/log.cpp
@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "threads.h"
|
#include "threads.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "gettime.h"
|
#include "gettime.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
@ -54,8 +54,8 @@ unsigned int android_log_level_mapping[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<ILogOutput*> log_outputs[LMT_NUM_VALUES];
|
std::vector<ILogOutput*> log_outputs[LMT_NUM_VALUES];
|
||||||
std::map<threadid_t, std::string> log_threadnames;
|
std::map<threadid_t, std::string> log_thread_names;
|
||||||
JMutex log_threadnamemutex;
|
Mutex log_thread_name_mutex;
|
||||||
|
|
||||||
void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
|
void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
|
||||||
{
|
{
|
||||||
@ -86,7 +86,7 @@ void log_remove_output(ILogOutput *out)
|
|||||||
|
|
||||||
void log_set_lev_silence(enum LogMessageLevel lev, bool silence)
|
void log_set_lev_silence(enum LogMessageLevel lev, bool silence)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(log_threadnamemutex);
|
MutexAutoLock lock(log_thread_name_mutex);
|
||||||
|
|
||||||
for (std::vector<ILogOutput *>::iterator it = log_outputs[lev].begin();
|
for (std::vector<ILogOutput *>::iterator it = log_outputs[lev].begin();
|
||||||
it != log_outputs[lev].end(); ++it) {
|
it != log_outputs[lev].end(); ++it) {
|
||||||
@ -98,17 +98,17 @@ void log_set_lev_silence(enum LogMessageLevel lev, bool silence)
|
|||||||
void log_register_thread(const std::string &name)
|
void log_register_thread(const std::string &name)
|
||||||
{
|
{
|
||||||
threadid_t id = get_current_thread_id();
|
threadid_t id = get_current_thread_id();
|
||||||
JMutexAutoLock lock(log_threadnamemutex);
|
MutexAutoLock lock(log_thread_name_mutex);
|
||||||
|
|
||||||
log_threadnames[id] = name;
|
log_thread_names[id] = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_deregister_thread()
|
void log_deregister_thread()
|
||||||
{
|
{
|
||||||
threadid_t id = get_current_thread_id();
|
threadid_t id = get_current_thread_id();
|
||||||
JMutexAutoLock lock(log_threadnamemutex);
|
MutexAutoLock lock(log_thread_name_mutex);
|
||||||
|
|
||||||
log_threadnames.erase(id);
|
log_thread_names.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_lev_string(enum LogMessageLevel lev)
|
static std::string get_lev_string(enum LogMessageLevel lev)
|
||||||
@ -130,11 +130,11 @@ static std::string get_lev_string(enum LogMessageLevel lev)
|
|||||||
|
|
||||||
void log_printline(enum LogMessageLevel lev, const std::string &text)
|
void log_printline(enum LogMessageLevel lev, const std::string &text)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(log_threadnamemutex);
|
MutexAutoLock lock(log_thread_name_mutex);
|
||||||
std::string threadname = "(unknown thread)";
|
std::string threadname = "(unknown thread)";
|
||||||
std::map<threadid_t, std::string>::const_iterator i;
|
std::map<threadid_t, std::string>::const_iterator i;
|
||||||
i = log_threadnames.find(get_current_thread_id());
|
i = log_thread_names.find(get_current_thread_id());
|
||||||
if(i != log_threadnames.end())
|
if(i != log_thread_names.end())
|
||||||
threadname = i->second;
|
threadname = i->second;
|
||||||
std::string levelname = get_lev_string(lev);
|
std::string levelname = get_lev_string(lev);
|
||||||
std::ostringstream os(std::ios_base::binary);
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
@ -153,7 +153,7 @@ int main(int argc, char *argv[])
|
|||||||
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
|
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
|
||||||
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
|
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
|
||||||
|
|
||||||
log_register_thread("main");
|
log_register_thread("Main");
|
||||||
|
|
||||||
Settings cmd_args;
|
Settings cmd_args;
|
||||||
bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args);
|
bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args);
|
||||||
|
@ -96,7 +96,7 @@ MapBlock::~MapBlock()
|
|||||||
{
|
{
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
{
|
{
|
||||||
//JMutexAutoLock lock(mesh_mutex);
|
//MutexAutoLock lock(mesh_mutex);
|
||||||
|
|
||||||
if(mesh)
|
if(mesh)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +139,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
#if 0
|
#if 0
|
||||||
printf("Decoration at (%d %d %d) cut off\n", x, y, z);
|
printf("Decoration at (%d %d %d) cut off\n", x, y, z);
|
||||||
//add to queue
|
//add to queue
|
||||||
JMutexAutoLock cutofflock(cutoff_mutex);
|
MutexAutoLock cutofflock(cutoff_mutex);
|
||||||
cutoffs.push_back(CutoffData(x, y, z, height));
|
cutoffs.push_back(CutoffData(x, y, z, height));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
// Copy over the cutoffs we're interested in so we don't needlessly hold a lock
|
// Copy over the cutoffs we're interested in so we don't needlessly hold a lock
|
||||||
{
|
{
|
||||||
JMutexAutoLock cutofflock(cutoff_mutex);
|
MutexAutoLock cutofflock(cutoff_mutex);
|
||||||
for (std::list<CutoffData>::iterator i = cutoffs.begin();
|
for (std::list<CutoffData>::iterator i = cutoffs.begin();
|
||||||
i != cutoffs.end(); ++i) {
|
i != cutoffs.end(); ++i) {
|
||||||
CutoffData cutoff = *i;
|
CutoffData cutoff = *i;
|
||||||
@ -203,7 +203,7 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
// Remove cutoffs that were handled from the cutoff list
|
// Remove cutoffs that were handled from the cutoff list
|
||||||
{
|
{
|
||||||
JMutexAutoLock cutofflock(cutoff_mutex);
|
MutexAutoLock cutofflock(cutoff_mutex);
|
||||||
for (std::list<CutoffData>::iterator i = cutoffs.begin();
|
for (std::list<CutoffData>::iterator i = cutoffs.begin();
|
||||||
i != cutoffs.end(); ++i) {
|
i != cutoffs.end(); ++i) {
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ public:
|
|||||||
|
|
||||||
std::set<u8> biomes;
|
std::set<u8> biomes;
|
||||||
//std::list<CutoffData> cutoffs;
|
//std::list<CutoffData> cutoffs;
|
||||||
//JMutex cutoff_mutex;
|
//Mutex cutoff_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DecoSimple : public Decoration {
|
class DecoSimple : public Decoration {
|
||||||
|
@ -20,8 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "logoutputbuffer.h"
|
#include "logoutputbuffer.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "jthread/jsemaphore.h"
|
#include "threading/semaphore.h"
|
||||||
#include "clientmap.h"
|
#include "clientmap.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
@ -52,7 +52,7 @@ MinimapUpdateThread::~MinimapUpdateThread()
|
|||||||
|
|
||||||
bool MinimapUpdateThread::pushBlockUpdate(v3s16 pos, MinimapMapblock *data)
|
bool MinimapUpdateThread::pushBlockUpdate(v3s16 pos, MinimapMapblock *data)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_queue_mutex);
|
MutexAutoLock lock(m_queue_mutex);
|
||||||
|
|
||||||
// Find if block is already in queue.
|
// Find if block is already in queue.
|
||||||
// If it is, update the data and quit.
|
// If it is, update the data and quit.
|
||||||
@ -78,7 +78,7 @@ bool MinimapUpdateThread::pushBlockUpdate(v3s16 pos, MinimapMapblock *data)
|
|||||||
|
|
||||||
bool MinimapUpdateThread::popBlockUpdate(QueuedMinimapUpdate *update)
|
bool MinimapUpdateThread::popBlockUpdate(QueuedMinimapUpdate *update)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_queue_mutex);
|
MutexAutoLock lock(m_queue_mutex);
|
||||||
|
|
||||||
if (m_update_queue.empty())
|
if (m_update_queue.empty())
|
||||||
return false;
|
return false;
|
||||||
@ -256,13 +256,13 @@ Mapper::Mapper(IrrlichtDevice *device, Client *client)
|
|||||||
// Initialize and start thread
|
// Initialize and start thread
|
||||||
m_minimap_update_thread = new MinimapUpdateThread();
|
m_minimap_update_thread = new MinimapUpdateThread();
|
||||||
m_minimap_update_thread->data = data;
|
m_minimap_update_thread->data = data;
|
||||||
m_minimap_update_thread->Start();
|
m_minimap_update_thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mapper::~Mapper()
|
Mapper::~Mapper()
|
||||||
{
|
{
|
||||||
m_minimap_update_thread->Stop();
|
m_minimap_update_thread->stop();
|
||||||
m_minimap_update_thread->Wait();
|
m_minimap_update_thread->wait();
|
||||||
|
|
||||||
m_meshbuffer->drop();
|
m_meshbuffer->drop();
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ MinimapMode Mapper::getMinimapMode()
|
|||||||
|
|
||||||
void Mapper::toggleMinimapShape()
|
void Mapper::toggleMinimapShape()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
data->minimap_shape_round = !data->minimap_shape_round;
|
data->minimap_shape_round = !data->minimap_shape_round;
|
||||||
g_settings->setBool("minimap_shape_round", data->minimap_shape_round);
|
g_settings->setBool("minimap_shape_round", data->minimap_shape_round);
|
||||||
@ -312,7 +312,7 @@ void Mapper::setMinimapMode(MinimapMode mode)
|
|||||||
if (mode >= MINIMAP_MODE_COUNT)
|
if (mode >= MINIMAP_MODE_COUNT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
data->is_radar = modedefs[mode].is_radar;
|
data->is_radar = modedefs[mode].is_radar;
|
||||||
data->scan_height = modedefs[mode].scan_height;
|
data->scan_height = modedefs[mode].scan_height;
|
||||||
@ -327,7 +327,7 @@ void Mapper::setPos(v3s16 pos)
|
|||||||
bool do_update = false;
|
bool do_update = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
if (pos != data->old_pos) {
|
if (pos != data->old_pos) {
|
||||||
data->old_pos = data->pos;
|
data->old_pos = data->pos;
|
||||||
|
@ -20,18 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#ifndef MINIMAP_HEADER
|
#ifndef MINIMAP_HEADER
|
||||||
#define MINIMAP_HEADER
|
#define MINIMAP_HEADER
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jsemaphore.h"
|
#include "threading/semaphore.h"
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define MINIMAP_MAX_SX 512
|
#define MINIMAP_MAX_SX 512
|
||||||
#define MINIMAP_MAX_SY 512
|
#define MINIMAP_MAX_SY 512
|
||||||
|
|
||||||
|
|
||||||
enum MinimapMode {
|
enum MinimapMode {
|
||||||
MINIMAP_MODE_OFF,
|
MINIMAP_MODE_OFF,
|
||||||
MINIMAP_MODE_SURFACEx1,
|
MINIMAP_MODE_SURFACEx1,
|
||||||
@ -90,6 +91,7 @@ struct QueuedMinimapUpdate {
|
|||||||
|
|
||||||
class MinimapUpdateThread : public UpdateThread {
|
class MinimapUpdateThread : public UpdateThread {
|
||||||
public:
|
public:
|
||||||
|
MinimapUpdateThread() : UpdateThread("Minimap") {}
|
||||||
virtual ~MinimapUpdateThread();
|
virtual ~MinimapUpdateThread();
|
||||||
|
|
||||||
void getMap(v3s16 pos, s16 size, s16 height, bool radar);
|
void getMap(v3s16 pos, s16 size, s16 height, bool radar);
|
||||||
@ -105,11 +107,10 @@ public:
|
|||||||
MinimapData *data;
|
MinimapData *data;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const char *getName() { return "MinimapUpdateThread"; }
|
|
||||||
virtual void doUpdate();
|
virtual void doUpdate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JMutex m_queue_mutex;
|
Mutex m_queue_mutex;
|
||||||
std::deque<QueuedMinimapUpdate> m_update_queue;
|
std::deque<QueuedMinimapUpdate> m_update_queue;
|
||||||
std::map<v3s16, MinimapMapblock *> m_blocks_cache;
|
std::map<v3s16, MinimapMapblock *> m_blocks_cache;
|
||||||
};
|
};
|
||||||
@ -151,7 +152,7 @@ private:
|
|||||||
bool m_enable_shaders;
|
bool m_enable_shaders;
|
||||||
u16 m_surface_mode_scan_height;
|
u16 m_surface_mode_scan_height;
|
||||||
f32 m_angle;
|
f32 m_angle;
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -621,7 +621,7 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
|
|||||||
|
|
||||||
// Mesh update thread must be stopped while
|
// Mesh update thread must be stopped while
|
||||||
// updating content definitions
|
// updating content definitions
|
||||||
sanity_check(!m_mesh_update_thread.IsRunning());
|
sanity_check(!m_mesh_update_thread.isRunning());
|
||||||
|
|
||||||
for (u16 i = 0; i < num_files; i++) {
|
for (u16 i = 0; i < num_files; i++) {
|
||||||
std::string name, sha1_base64;
|
std::string name, sha1_base64;
|
||||||
@ -694,7 +694,7 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
|
|||||||
|
|
||||||
// Mesh update thread must be stopped while
|
// Mesh update thread must be stopped while
|
||||||
// updating content definitions
|
// updating content definitions
|
||||||
sanity_check(!m_mesh_update_thread.IsRunning());
|
sanity_check(!m_mesh_update_thread.isRunning());
|
||||||
|
|
||||||
for (u32 i=0; i < num_files; i++) {
|
for (u32 i=0; i < num_files; i++) {
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -720,7 +720,7 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
|
|||||||
|
|
||||||
// Mesh update thread must be stopped while
|
// Mesh update thread must be stopped while
|
||||||
// updating content definitions
|
// updating content definitions
|
||||||
sanity_check(!m_mesh_update_thread.IsRunning());
|
sanity_check(!m_mesh_update_thread.isRunning());
|
||||||
|
|
||||||
// Decompress node definitions
|
// Decompress node definitions
|
||||||
std::string datastring(pkt->getString(0), pkt->getSize());
|
std::string datastring(pkt->getString(0), pkt->getSize());
|
||||||
@ -747,7 +747,7 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
|
|||||||
|
|
||||||
// Mesh update thread must be stopped while
|
// Mesh update thread must be stopped while
|
||||||
// updating content definitions
|
// updating content definitions
|
||||||
sanity_check(!m_mesh_update_thread.IsRunning());
|
sanity_check(!m_mesh_update_thread.isRunning());
|
||||||
|
|
||||||
// Decompress item definitions
|
// Decompress item definitions
|
||||||
std::string datastring(pkt->getString(0), pkt->getSize());
|
std::string datastring(pkt->getString(0), pkt->getSize());
|
||||||
|
@ -42,10 +42,10 @@ namespace con
|
|||||||
#undef DEBUG_CONNECTION_KBPS
|
#undef DEBUG_CONNECTION_KBPS
|
||||||
#else
|
#else
|
||||||
/* this mutex is used to achieve log message consistency */
|
/* this mutex is used to achieve log message consistency */
|
||||||
JMutex log_message_mutex;
|
Mutex log_message_mutex;
|
||||||
#define LOG(a) \
|
#define LOG(a) \
|
||||||
{ \
|
{ \
|
||||||
JMutexAutoLock loglock(log_message_mutex); \
|
MutexAutoLock loglock(log_message_mutex); \
|
||||||
a; \
|
a; \
|
||||||
}
|
}
|
||||||
#define PROFILE(a) a
|
#define PROFILE(a) a
|
||||||
@ -209,7 +209,7 @@ ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0) {}
|
|||||||
|
|
||||||
void ReliablePacketBuffer::print()
|
void ReliablePacketBuffer::print()
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl);
|
LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl);
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
||||||
@ -223,7 +223,7 @@ void ReliablePacketBuffer::print()
|
|||||||
}
|
}
|
||||||
bool ReliablePacketBuffer::empty()
|
bool ReliablePacketBuffer::empty()
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
return m_list.empty();
|
return m_list.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ RPBSearchResult ReliablePacketBuffer::notFound()
|
|||||||
}
|
}
|
||||||
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (m_list.empty())
|
if (m_list.empty())
|
||||||
return false;
|
return false;
|
||||||
BufferedPacket p = *m_list.begin();
|
BufferedPacket p = *m_list.begin();
|
||||||
@ -266,7 +266,7 @@ bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
|
|||||||
|
|
||||||
BufferedPacket ReliablePacketBuffer::popFirst()
|
BufferedPacket ReliablePacketBuffer::popFirst()
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (m_list.empty())
|
if (m_list.empty())
|
||||||
throw NotFoundException("Buffer is empty");
|
throw NotFoundException("Buffer is empty");
|
||||||
BufferedPacket p = *m_list.begin();
|
BufferedPacket p = *m_list.begin();
|
||||||
@ -283,7 +283,7 @@ BufferedPacket ReliablePacketBuffer::popFirst()
|
|||||||
}
|
}
|
||||||
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
|
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
RPBSearchResult r = findPacket(seqnum);
|
RPBSearchResult r = findPacket(seqnum);
|
||||||
if (r == notFound()) {
|
if (r == notFound()) {
|
||||||
LOG(dout_con<<"Sequence number: " << seqnum
|
LOG(dout_con<<"Sequence number: " << seqnum
|
||||||
@ -311,7 +311,7 @@ BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
|
|||||||
}
|
}
|
||||||
void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
|
void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
if (p.data.getSize() < BASE_HEADER_SIZE + 3) {
|
if (p.data.getSize() < BASE_HEADER_SIZE + 3) {
|
||||||
errorstream << "ReliablePacketBuffer::insert(): Invalid data size for "
|
errorstream << "ReliablePacketBuffer::insert(): Invalid data size for "
|
||||||
"reliable packet" << std::endl;
|
"reliable packet" << std::endl;
|
||||||
@ -411,7 +411,7 @@ void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
|
|||||||
|
|
||||||
void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
||||||
i != m_list.end(); ++i)
|
i != m_list.end(); ++i)
|
||||||
{
|
{
|
||||||
@ -423,7 +423,7 @@ void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
|||||||
std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout,
|
std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout,
|
||||||
unsigned int max_packets)
|
unsigned int max_packets)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_list_mutex);
|
MutexAutoLock listlock(m_list_mutex);
|
||||||
std::list<BufferedPacket> timed_outs;
|
std::list<BufferedPacket> timed_outs;
|
||||||
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
for(std::list<BufferedPacket>::iterator i = m_list.begin();
|
||||||
i != m_list.end(); ++i)
|
i != m_list.end(); ++i)
|
||||||
@ -446,7 +446,7 @@ std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout,
|
|||||||
|
|
||||||
IncomingSplitBuffer::~IncomingSplitBuffer()
|
IncomingSplitBuffer::~IncomingSplitBuffer()
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_map_mutex);
|
MutexAutoLock listlock(m_map_mutex);
|
||||||
for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
|
for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
|
||||||
i != m_buf.end(); ++i)
|
i != m_buf.end(); ++i)
|
||||||
{
|
{
|
||||||
@ -459,7 +459,7 @@ IncomingSplitBuffer::~IncomingSplitBuffer()
|
|||||||
*/
|
*/
|
||||||
SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
|
SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_map_mutex);
|
MutexAutoLock listlock(m_map_mutex);
|
||||||
u32 headersize = BASE_HEADER_SIZE + 7;
|
u32 headersize = BASE_HEADER_SIZE + 7;
|
||||||
if (p.data.getSize() < headersize) {
|
if (p.data.getSize() < headersize) {
|
||||||
errorstream << "Invalid data size for split packet" << std::endl;
|
errorstream << "Invalid data size for split packet" << std::endl;
|
||||||
@ -546,7 +546,7 @@ void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
|
|||||||
{
|
{
|
||||||
std::list<u16> remove_queue;
|
std::list<u16> remove_queue;
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_map_mutex);
|
MutexAutoLock listlock(m_map_mutex);
|
||||||
for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
|
for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
|
||||||
i != m_buf.end(); ++i)
|
i != m_buf.end(); ++i)
|
||||||
{
|
{
|
||||||
@ -562,7 +562,7 @@ void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
|
|||||||
for(std::list<u16>::iterator j = remove_queue.begin();
|
for(std::list<u16>::iterator j = remove_queue.begin();
|
||||||
j != remove_queue.end(); ++j)
|
j != remove_queue.end(); ++j)
|
||||||
{
|
{
|
||||||
JMutexAutoLock listlock(m_map_mutex);
|
MutexAutoLock listlock(m_map_mutex);
|
||||||
LOG(dout_con<<"NOTE: Removing timed out unreliable split packet"<<std::endl);
|
LOG(dout_con<<"NOTE: Removing timed out unreliable split packet"<<std::endl);
|
||||||
delete m_buf[*j];
|
delete m_buf[*j];
|
||||||
m_buf.erase(*j);
|
m_buf.erase(*j);
|
||||||
@ -605,13 +605,13 @@ Channel::~Channel()
|
|||||||
|
|
||||||
u16 Channel::readNextIncomingSeqNum()
|
u16 Channel::readNextIncomingSeqNum()
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
return next_incoming_seqnum;
|
return next_incoming_seqnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 Channel::incNextIncomingSeqNum()
|
u16 Channel::incNextIncomingSeqNum()
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
u16 retval = next_incoming_seqnum;
|
u16 retval = next_incoming_seqnum;
|
||||||
next_incoming_seqnum++;
|
next_incoming_seqnum++;
|
||||||
return retval;
|
return retval;
|
||||||
@ -619,18 +619,18 @@ u16 Channel::incNextIncomingSeqNum()
|
|||||||
|
|
||||||
u16 Channel::readNextSplitSeqNum()
|
u16 Channel::readNextSplitSeqNum()
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
return next_outgoing_split_seqnum;
|
return next_outgoing_split_seqnum;
|
||||||
}
|
}
|
||||||
void Channel::setNextSplitSeqNum(u16 seqnum)
|
void Channel::setNextSplitSeqNum(u16 seqnum)
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
next_outgoing_split_seqnum = seqnum;
|
next_outgoing_split_seqnum = seqnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 Channel::getOutgoingSequenceNumber(bool& successful)
|
u16 Channel::getOutgoingSequenceNumber(bool& successful)
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
u16 retval = next_outgoing_seqnum;
|
u16 retval = next_outgoing_seqnum;
|
||||||
u16 lowest_unacked_seqnumber;
|
u16 lowest_unacked_seqnumber;
|
||||||
|
|
||||||
@ -670,7 +670,7 @@ u16 Channel::getOutgoingSequenceNumber(bool& successful)
|
|||||||
|
|
||||||
u16 Channel::readOutgoingSequenceNumber()
|
u16 Channel::readOutgoingSequenceNumber()
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
return next_outgoing_seqnum;
|
return next_outgoing_seqnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,32 +686,32 @@ bool Channel::putBackSequenceNumber(u16 seqnum)
|
|||||||
|
|
||||||
void Channel::UpdateBytesSent(unsigned int bytes, unsigned int packets)
|
void Channel::UpdateBytesSent(unsigned int bytes, unsigned int packets)
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
current_bytes_transfered += bytes;
|
current_bytes_transfered += bytes;
|
||||||
current_packet_successfull += packets;
|
current_packet_successfull += packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::UpdateBytesReceived(unsigned int bytes) {
|
void Channel::UpdateBytesReceived(unsigned int bytes) {
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
current_bytes_received += bytes;
|
current_bytes_received += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::UpdateBytesLost(unsigned int bytes)
|
void Channel::UpdateBytesLost(unsigned int bytes)
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
current_bytes_lost += bytes;
|
current_bytes_lost += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Channel::UpdatePacketLossCounter(unsigned int count)
|
void Channel::UpdatePacketLossCounter(unsigned int count)
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
current_packet_loss += count;
|
current_packet_loss += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::UpdatePacketTooLateCounter()
|
void Channel::UpdatePacketTooLateCounter()
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
current_packet_too_late++;
|
current_packet_too_late++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +731,7 @@ void Channel::UpdateTimers(float dtime,bool legacy_peer)
|
|||||||
bool reasonable_amount_of_data_transmitted = false;
|
bool reasonable_amount_of_data_transmitted = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
packet_loss = current_packet_loss;
|
packet_loss = current_packet_loss;
|
||||||
//packet_too_late = current_packet_too_late;
|
//packet_too_late = current_packet_too_late;
|
||||||
packets_successfull = current_packet_successfull;
|
packets_successfull = current_packet_successfull;
|
||||||
@ -802,7 +802,7 @@ void Channel::UpdateTimers(float dtime,bool legacy_peer)
|
|||||||
if (bpm_counter > 10.0)
|
if (bpm_counter > 10.0)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
JMutexAutoLock internal(m_internal_mutex);
|
MutexAutoLock internal(m_internal_mutex);
|
||||||
cur_kbps =
|
cur_kbps =
|
||||||
(((float) current_bytes_transfered)/bpm_counter)/1024.0;
|
(((float) current_bytes_transfered)/bpm_counter)/1024.0;
|
||||||
current_bytes_transfered = 0;
|
current_bytes_transfered = 0;
|
||||||
@ -903,7 +903,7 @@ bool PeerHelper::operator!=(void* ptr)
|
|||||||
|
|
||||||
bool Peer::IncUseCount()
|
bool Peer::IncUseCount()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_exclusive_access_mutex);
|
MutexAutoLock lock(m_exclusive_access_mutex);
|
||||||
|
|
||||||
if (!m_pending_deletion)
|
if (!m_pending_deletion)
|
||||||
{
|
{
|
||||||
@ -917,7 +917,7 @@ bool Peer::IncUseCount()
|
|||||||
void Peer::DecUseCount()
|
void Peer::DecUseCount()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_exclusive_access_mutex);
|
MutexAutoLock lock(m_exclusive_access_mutex);
|
||||||
sanity_check(m_usage > 0);
|
sanity_check(m_usage > 0);
|
||||||
m_usage--;
|
m_usage--;
|
||||||
|
|
||||||
@ -978,7 +978,7 @@ void Peer::RTTStatistics(float rtt, std::string profiler_id,
|
|||||||
|
|
||||||
bool Peer::isTimedOut(float timeout)
|
bool Peer::isTimedOut(float timeout)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_exclusive_access_mutex);
|
MutexAutoLock lock(m_exclusive_access_mutex);
|
||||||
u32 current_time = porting::getTimeMs();
|
u32 current_time = porting::getTimeMs();
|
||||||
|
|
||||||
float dtime = CALC_DTIME(m_last_timeout_check,current_time);
|
float dtime = CALC_DTIME(m_last_timeout_check,current_time);
|
||||||
@ -992,7 +992,7 @@ bool Peer::isTimedOut(float timeout)
|
|||||||
void Peer::Drop()
|
void Peer::Drop()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
JMutexAutoLock usage_lock(m_exclusive_access_mutex);
|
MutexAutoLock usage_lock(m_exclusive_access_mutex);
|
||||||
m_pending_deletion = true;
|
m_pending_deletion = true;
|
||||||
if (m_usage != 0)
|
if (m_usage != 0)
|
||||||
return;
|
return;
|
||||||
@ -1051,7 +1051,7 @@ void UDPPeer::reportRTT(float rtt)
|
|||||||
if (timeout > RESEND_TIMEOUT_MAX)
|
if (timeout > RESEND_TIMEOUT_MAX)
|
||||||
timeout = RESEND_TIMEOUT_MAX;
|
timeout = RESEND_TIMEOUT_MAX;
|
||||||
|
|
||||||
JMutexAutoLock usage_lock(m_exclusive_access_mutex);
|
MutexAutoLock usage_lock(m_exclusive_access_mutex);
|
||||||
resend_timeout = timeout;
|
resend_timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,8 +1255,9 @@ SharedBuffer<u8> UDPPeer::addSpiltPacket(u8 channel,
|
|||||||
/* Connection Threads */
|
/* Connection Threads */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
ConnectionSendThread::ConnectionSendThread( unsigned int max_packet_size,
|
ConnectionSendThread::ConnectionSendThread(unsigned int max_packet_size,
|
||||||
float timeout) :
|
float timeout) :
|
||||||
|
Thread("ConnectionSend"),
|
||||||
m_connection(NULL),
|
m_connection(NULL),
|
||||||
m_max_packet_size(max_packet_size),
|
m_max_packet_size(max_packet_size),
|
||||||
m_timeout(timeout),
|
m_timeout(timeout),
|
||||||
@ -1266,11 +1267,9 @@ ConnectionSendThread::ConnectionSendThread( unsigned int max_packet_size,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void * ConnectionSendThread::Thread()
|
void * ConnectionSendThread::run()
|
||||||
{
|
{
|
||||||
assert(m_connection != NULL);
|
assert(m_connection);
|
||||||
ThreadStarted();
|
|
||||||
log_register_thread("ConnectionSend");
|
|
||||||
|
|
||||||
LOG(dout_con<<m_connection->getDesc()
|
LOG(dout_con<<m_connection->getDesc()
|
||||||
<<"ConnectionSend thread started"<<std::endl);
|
<<"ConnectionSend thread started"<<std::endl);
|
||||||
@ -1281,21 +1280,19 @@ void * ConnectionSendThread::Thread()
|
|||||||
PROFILE(std::stringstream ThreadIdentifier);
|
PROFILE(std::stringstream ThreadIdentifier);
|
||||||
PROFILE(ThreadIdentifier << "ConnectionSend: [" << m_connection->getDesc() << "]");
|
PROFILE(ThreadIdentifier << "ConnectionSend: [" << m_connection->getDesc() << "]");
|
||||||
|
|
||||||
porting::setThreadName("ConnectionSend");
|
|
||||||
|
|
||||||
/* if stop is requested don't stop immediately but try to send all */
|
/* if stop is requested don't stop immediately but try to send all */
|
||||||
/* packets first */
|
/* packets first */
|
||||||
while(!StopRequested() || packetsQueued()) {
|
while(!stopRequested() || packetsQueued()) {
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
PROFILE(ScopeProfiler sp(g_profiler, ThreadIdentifier.str(), SPT_AVG));
|
PROFILE(ScopeProfiler sp(g_profiler, ThreadIdentifier.str(), SPT_AVG));
|
||||||
|
|
||||||
m_iteration_packets_avaialble = m_max_data_packets_per_iteration;
|
m_iteration_packets_avaialble = m_max_data_packets_per_iteration;
|
||||||
|
|
||||||
/* wait for trigger or timeout */
|
/* wait for trigger or timeout */
|
||||||
m_send_sleep_semaphore.Wait(50);
|
m_send_sleep_semaphore.wait(50);
|
||||||
|
|
||||||
/* remove all triggers */
|
/* remove all triggers */
|
||||||
while(m_send_sleep_semaphore.Wait(0)) {}
|
while(m_send_sleep_semaphore.wait(0)) {}
|
||||||
|
|
||||||
lasttime = curtime;
|
lasttime = curtime;
|
||||||
curtime = porting::getTimeMs();
|
curtime = porting::getTimeMs();
|
||||||
@ -1328,7 +1325,7 @@ void * ConnectionSendThread::Thread()
|
|||||||
|
|
||||||
void ConnectionSendThread::Trigger()
|
void ConnectionSendThread::Trigger()
|
||||||
{
|
{
|
||||||
m_send_sleep_semaphore.Post();
|
m_send_sleep_semaphore.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectionSendThread::packetsQueued()
|
bool ConnectionSendThread::packetsQueued()
|
||||||
@ -1984,7 +1981,7 @@ void ConnectionSendThread::sendPackets(float dtime)
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
( peer->m_increment_packets_remaining > 0) ||
|
( peer->m_increment_packets_remaining > 0) ||
|
||||||
(StopRequested())) {
|
(stopRequested())) {
|
||||||
rawSendAsPacket(packet.peer_id, packet.channelnum,
|
rawSendAsPacket(packet.peer_id, packet.channelnum,
|
||||||
packet.data, packet.reliable);
|
packet.data, packet.reliable);
|
||||||
peer->m_increment_packets_remaining--;
|
peer->m_increment_packets_remaining--;
|
||||||
@ -2014,15 +2011,14 @@ void ConnectionSendThread::sendAsPacket(u16 peer_id, u8 channelnum,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConnectionReceiveThread::ConnectionReceiveThread(unsigned int max_packet_size) :
|
ConnectionReceiveThread::ConnectionReceiveThread(unsigned int max_packet_size) :
|
||||||
|
Thread("ConnectionReceive"),
|
||||||
m_connection(NULL)
|
m_connection(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void * ConnectionReceiveThread::Thread()
|
void * ConnectionReceiveThread::run()
|
||||||
{
|
{
|
||||||
assert(m_connection != NULL);
|
assert(m_connection);
|
||||||
ThreadStarted();
|
|
||||||
log_register_thread("ConnectionReceive");
|
|
||||||
|
|
||||||
LOG(dout_con<<m_connection->getDesc()
|
LOG(dout_con<<m_connection->getDesc()
|
||||||
<<"ConnectionReceive thread started"<<std::endl);
|
<<"ConnectionReceive thread started"<<std::endl);
|
||||||
@ -2030,15 +2026,13 @@ void * ConnectionReceiveThread::Thread()
|
|||||||
PROFILE(std::stringstream ThreadIdentifier);
|
PROFILE(std::stringstream ThreadIdentifier);
|
||||||
PROFILE(ThreadIdentifier << "ConnectionReceive: [" << m_connection->getDesc() << "]");
|
PROFILE(ThreadIdentifier << "ConnectionReceive: [" << m_connection->getDesc() << "]");
|
||||||
|
|
||||||
porting::setThreadName("ConnectionReceive");
|
|
||||||
|
|
||||||
#ifdef DEBUG_CONNECTION_KBPS
|
#ifdef DEBUG_CONNECTION_KBPS
|
||||||
u32 curtime = porting::getTimeMs();
|
u32 curtime = porting::getTimeMs();
|
||||||
u32 lasttime = curtime;
|
u32 lasttime = curtime;
|
||||||
float debug_print_timer = 0.0;
|
float debug_print_timer = 0.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while(!StopRequested()) {
|
while(!stopRequested()) {
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
PROFILE(ScopeProfiler sp(g_profiler, ThreadIdentifier.str(), SPT_AVG));
|
PROFILE(ScopeProfiler sp(g_profiler, ThreadIdentifier.str(), SPT_AVG));
|
||||||
|
|
||||||
@ -2684,8 +2678,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
|
|||||||
m_sendThread.setParent(this);
|
m_sendThread.setParent(this);
|
||||||
m_receiveThread.setParent(this);
|
m_receiveThread.setParent(this);
|
||||||
|
|
||||||
m_sendThread.Start();
|
m_sendThread.start();
|
||||||
m_receiveThread.Start();
|
m_receiveThread.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2694,8 +2688,8 @@ Connection::~Connection()
|
|||||||
{
|
{
|
||||||
m_shutting_down = true;
|
m_shutting_down = true;
|
||||||
// request threads to stop
|
// request threads to stop
|
||||||
m_sendThread.Stop();
|
m_sendThread.stop();
|
||||||
m_receiveThread.Stop();
|
m_receiveThread.stop();
|
||||||
|
|
||||||
//TODO for some unkonwn reason send/receive threads do not exit as they're
|
//TODO for some unkonwn reason send/receive threads do not exit as they're
|
||||||
// supposed to be but wait on peer timeout. To speed up shutdown we reduce
|
// supposed to be but wait on peer timeout. To speed up shutdown we reduce
|
||||||
@ -2703,8 +2697,8 @@ Connection::~Connection()
|
|||||||
m_sendThread.setPeerTimeout(0.5);
|
m_sendThread.setPeerTimeout(0.5);
|
||||||
|
|
||||||
// wait for threads to finish
|
// wait for threads to finish
|
||||||
m_sendThread.Wait();
|
m_sendThread.wait();
|
||||||
m_receiveThread.Wait();
|
m_receiveThread.wait();
|
||||||
|
|
||||||
// Delete peers
|
// Delete peers
|
||||||
for(std::map<u16, Peer*>::iterator
|
for(std::map<u16, Peer*>::iterator
|
||||||
@ -2724,7 +2718,7 @@ void Connection::putEvent(ConnectionEvent &e)
|
|||||||
|
|
||||||
PeerHelper Connection::getPeer(u16 peer_id)
|
PeerHelper Connection::getPeer(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
|
std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
|
||||||
|
|
||||||
if (node == m_peers.end()) {
|
if (node == m_peers.end()) {
|
||||||
@ -2739,7 +2733,7 @@ PeerHelper Connection::getPeer(u16 peer_id)
|
|||||||
|
|
||||||
PeerHelper Connection::getPeerNoEx(u16 peer_id)
|
PeerHelper Connection::getPeerNoEx(u16 peer_id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
|
std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
|
||||||
|
|
||||||
if (node == m_peers.end()) {
|
if (node == m_peers.end()) {
|
||||||
@ -2755,7 +2749,7 @@ PeerHelper Connection::getPeerNoEx(u16 peer_id)
|
|||||||
/* find peer_id for address */
|
/* find peer_id for address */
|
||||||
u16 Connection::lookupPeer(Address& sender)
|
u16 Connection::lookupPeer(Address& sender)
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
std::map<u16, Peer*>::iterator j;
|
std::map<u16, Peer*>::iterator j;
|
||||||
j = m_peers.begin();
|
j = m_peers.begin();
|
||||||
for(; j != m_peers.end(); ++j)
|
for(; j != m_peers.end(); ++j)
|
||||||
@ -2794,7 +2788,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
|
|||||||
|
|
||||||
/* lock list as short as possible */
|
/* lock list as short as possible */
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
if (m_peers.find(peer_id) == m_peers.end())
|
if (m_peers.find(peer_id) == m_peers.end())
|
||||||
return false;
|
return false;
|
||||||
peer = m_peers[peer_id];
|
peer = m_peers[peer_id];
|
||||||
@ -2852,7 +2846,7 @@ void Connection::Connect(Address address)
|
|||||||
|
|
||||||
bool Connection::Connected()
|
bool Connection::Connected()
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
|
|
||||||
if (m_peers.size() != 1)
|
if (m_peers.size() != 1)
|
||||||
return false;
|
return false;
|
||||||
@ -2987,7 +2981,7 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
|||||||
/*
|
/*
|
||||||
Find an unused peer id
|
Find an unused peer id
|
||||||
*/
|
*/
|
||||||
JMutexAutoLock lock(m_peers_mutex);
|
MutexAutoLock lock(m_peers_mutex);
|
||||||
bool out_of_ids = false;
|
bool out_of_ids = false;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Check if exists
|
// Check if exists
|
||||||
@ -3038,9 +3032,9 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
|||||||
|
|
||||||
void Connection::PrintInfo(std::ostream &out)
|
void Connection::PrintInfo(std::ostream &out)
|
||||||
{
|
{
|
||||||
m_info_mutex.Lock();
|
m_info_mutex.lock();
|
||||||
out<<getDesc()<<": ";
|
out<<getDesc()<<": ";
|
||||||
m_info_mutex.Unlock();
|
m_info_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::PrintInfo()
|
void Connection::PrintInfo()
|
||||||
@ -3091,7 +3085,7 @@ UDPPeer* Connection::createServerPeer(Address& address)
|
|||||||
UDPPeer *peer = new UDPPeer(PEER_ID_SERVER, address, this);
|
UDPPeer *peer = new UDPPeer(PEER_ID_SERVER, address, this);
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_peers_mutex);
|
MutexAutoLock lock(m_peers_mutex);
|
||||||
m_peers[peer->id] = peer;
|
m_peers[peer->id] = peer;
|
||||||
m_peer_ids.push_back(peer->id);
|
m_peer_ids.push_back(peer->id);
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ private:
|
|||||||
|
|
||||||
u16 m_oldest_non_answered_ack;
|
u16 m_oldest_non_answered_ack;
|
||||||
|
|
||||||
JMutex m_list_mutex;
|
Mutex m_list_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -372,7 +372,7 @@ private:
|
|||||||
// Key is seqnum
|
// Key is seqnum
|
||||||
std::map<u16, IncomingSplitPacket*> m_buf;
|
std::map<u16, IncomingSplitPacket*> m_buf;
|
||||||
|
|
||||||
JMutex m_map_mutex;
|
Mutex m_map_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutgoingPacket
|
struct OutgoingPacket
|
||||||
@ -519,32 +519,32 @@ public:
|
|||||||
void UpdateTimers(float dtime, bool legacy_peer);
|
void UpdateTimers(float dtime, bool legacy_peer);
|
||||||
|
|
||||||
const float getCurrentDownloadRateKB()
|
const float getCurrentDownloadRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return cur_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return cur_kbps; };
|
||||||
const float getMaxDownloadRateKB()
|
const float getMaxDownloadRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return max_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return max_kbps; };
|
||||||
|
|
||||||
const float getCurrentLossRateKB()
|
const float getCurrentLossRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return cur_kbps_lost; };
|
{ MutexAutoLock lock(m_internal_mutex); return cur_kbps_lost; };
|
||||||
const float getMaxLossRateKB()
|
const float getMaxLossRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return max_kbps_lost; };
|
{ MutexAutoLock lock(m_internal_mutex); return max_kbps_lost; };
|
||||||
|
|
||||||
const float getCurrentIncomingRateKB()
|
const float getCurrentIncomingRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return cur_incoming_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return cur_incoming_kbps; };
|
||||||
const float getMaxIncomingRateKB()
|
const float getMaxIncomingRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return max_incoming_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return max_incoming_kbps; };
|
||||||
|
|
||||||
const float getAvgDownloadRateKB()
|
const float getAvgDownloadRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return avg_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return avg_kbps; };
|
||||||
const float getAvgLossRateKB()
|
const float getAvgLossRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return avg_kbps_lost; };
|
{ MutexAutoLock lock(m_internal_mutex); return avg_kbps_lost; };
|
||||||
const float getAvgIncomingRateKB()
|
const float getAvgIncomingRateKB()
|
||||||
{ JMutexAutoLock lock(m_internal_mutex); return avg_incoming_kbps; };
|
{ MutexAutoLock lock(m_internal_mutex); return avg_incoming_kbps; };
|
||||||
|
|
||||||
const unsigned int getWindowSize() const { return window_size; };
|
const unsigned int getWindowSize() const { return window_size; };
|
||||||
|
|
||||||
void setWindowSize(unsigned int size) { window_size = size; };
|
void setWindowSize(unsigned int size) { window_size = size; };
|
||||||
private:
|
private:
|
||||||
JMutex m_internal_mutex;
|
Mutex m_internal_mutex;
|
||||||
int window_size;
|
int window_size;
|
||||||
|
|
||||||
u16 next_incoming_seqnum;
|
u16 next_incoming_seqnum;
|
||||||
@ -675,7 +675,7 @@ class Peer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Peer() {
|
virtual ~Peer() {
|
||||||
JMutexAutoLock usage_lock(m_exclusive_access_mutex);
|
MutexAutoLock usage_lock(m_exclusive_access_mutex);
|
||||||
FATAL_ERROR_IF(m_usage != 0, "Reference counting failure");
|
FATAL_ERROR_IF(m_usage != 0, "Reference counting failure");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -692,15 +692,15 @@ class Peer {
|
|||||||
virtual bool getAddress(MTProtocols type, Address& toset) = 0;
|
virtual bool getAddress(MTProtocols type, Address& toset) = 0;
|
||||||
|
|
||||||
void ResetTimeout()
|
void ResetTimeout()
|
||||||
{JMutexAutoLock lock(m_exclusive_access_mutex); m_timeout_counter=0.0; };
|
{MutexAutoLock lock(m_exclusive_access_mutex); m_timeout_counter=0.0; };
|
||||||
|
|
||||||
bool isTimedOut(float timeout);
|
bool isTimedOut(float timeout);
|
||||||
|
|
||||||
void setSentWithID()
|
void setSentWithID()
|
||||||
{ JMutexAutoLock lock(m_exclusive_access_mutex); m_has_sent_with_id = true; };
|
{ MutexAutoLock lock(m_exclusive_access_mutex); m_has_sent_with_id = true; };
|
||||||
|
|
||||||
bool hasSentWithID()
|
bool hasSentWithID()
|
||||||
{ JMutexAutoLock lock(m_exclusive_access_mutex); return m_has_sent_with_id; };
|
{ MutexAutoLock lock(m_exclusive_access_mutex); return m_has_sent_with_id; };
|
||||||
|
|
||||||
unsigned int m_increment_packets_remaining;
|
unsigned int m_increment_packets_remaining;
|
||||||
unsigned int m_increment_bytes_remaining;
|
unsigned int m_increment_bytes_remaining;
|
||||||
@ -744,7 +744,7 @@ class Peer {
|
|||||||
bool IncUseCount();
|
bool IncUseCount();
|
||||||
void DecUseCount();
|
void DecUseCount();
|
||||||
|
|
||||||
JMutex m_exclusive_access_mutex;
|
Mutex m_exclusive_access_mutex;
|
||||||
|
|
||||||
bool m_pending_deletion;
|
bool m_pending_deletion;
|
||||||
|
|
||||||
@ -826,10 +826,10 @@ protected:
|
|||||||
unsigned int maxtransfer);
|
unsigned int maxtransfer);
|
||||||
|
|
||||||
float getResendTimeout()
|
float getResendTimeout()
|
||||||
{ JMutexAutoLock lock(m_exclusive_access_mutex); return resend_timeout; }
|
{ MutexAutoLock lock(m_exclusive_access_mutex); return resend_timeout; }
|
||||||
|
|
||||||
void setResendTimeout(float timeout)
|
void setResendTimeout(float timeout)
|
||||||
{ JMutexAutoLock lock(m_exclusive_access_mutex); resend_timeout = timeout; }
|
{ MutexAutoLock lock(m_exclusive_access_mutex); resend_timeout = timeout; }
|
||||||
bool Ping(float dtime,SharedBuffer<u8>& data);
|
bool Ping(float dtime,SharedBuffer<u8>& data);
|
||||||
|
|
||||||
Channel channels[CHANNEL_COUNT];
|
Channel channels[CHANNEL_COUNT];
|
||||||
@ -910,14 +910,14 @@ struct ConnectionEvent
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConnectionSendThread : public JThread {
|
class ConnectionSendThread : public Thread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend class UDPPeer;
|
friend class UDPPeer;
|
||||||
|
|
||||||
ConnectionSendThread(unsigned int max_packet_size, float timeout);
|
ConnectionSendThread(unsigned int max_packet_size, float timeout);
|
||||||
|
|
||||||
void * Thread ();
|
void *run();
|
||||||
|
|
||||||
void Trigger();
|
void Trigger();
|
||||||
|
|
||||||
@ -961,7 +961,7 @@ private:
|
|||||||
unsigned int m_max_packet_size;
|
unsigned int m_max_packet_size;
|
||||||
float m_timeout;
|
float m_timeout;
|
||||||
std::queue<OutgoingPacket> m_outgoing_queue;
|
std::queue<OutgoingPacket> m_outgoing_queue;
|
||||||
JSemaphore m_send_sleep_semaphore;
|
Semaphore m_send_sleep_semaphore;
|
||||||
|
|
||||||
unsigned int m_iteration_packets_avaialble;
|
unsigned int m_iteration_packets_avaialble;
|
||||||
unsigned int m_max_commands_per_iteration;
|
unsigned int m_max_commands_per_iteration;
|
||||||
@ -969,24 +969,24 @@ private:
|
|||||||
unsigned int m_max_packets_requeued;
|
unsigned int m_max_packets_requeued;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConnectionReceiveThread : public JThread {
|
class ConnectionReceiveThread : public Thread {
|
||||||
public:
|
public:
|
||||||
ConnectionReceiveThread(unsigned int max_packet_size);
|
ConnectionReceiveThread(unsigned int max_packet_size);
|
||||||
|
|
||||||
void * Thread ();
|
void *run();
|
||||||
|
|
||||||
void setParent(Connection* parent) {
|
void setParent(Connection *parent) {
|
||||||
assert(parent != NULL); // Pre-condition
|
assert(parent); // Pre-condition
|
||||||
m_connection = parent;
|
m_connection = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void receive ();
|
void receive();
|
||||||
|
|
||||||
// Returns next data from a buffer if possible
|
// Returns next data from a buffer if possible
|
||||||
// If found, returns true; if not, false.
|
// If found, returns true; if not, false.
|
||||||
// If found, sets peer_id and dst
|
// If found, sets peer_id and dst
|
||||||
bool getFromBuffers (u16 &peer_id, SharedBuffer<u8> &dst);
|
bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst);
|
||||||
|
|
||||||
bool checkIncomingBuffers(Channel *channel, u16 &peer_id,
|
bool checkIncomingBuffers(Channel *channel, u16 &peer_id,
|
||||||
SharedBuffer<u8> &dst);
|
SharedBuffer<u8> &dst);
|
||||||
@ -1054,7 +1054,7 @@ protected:
|
|||||||
|
|
||||||
std::list<u16> getPeerIDs()
|
std::list<u16> getPeerIDs()
|
||||||
{
|
{
|
||||||
JMutexAutoLock peerlock(m_peers_mutex);
|
MutexAutoLock peerlock(m_peers_mutex);
|
||||||
return m_peer_ids;
|
return m_peer_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,12 +1075,12 @@ private:
|
|||||||
|
|
||||||
std::map<u16, Peer*> m_peers;
|
std::map<u16, Peer*> m_peers;
|
||||||
std::list<u16> m_peer_ids;
|
std::list<u16> m_peer_ids;
|
||||||
JMutex m_peers_mutex;
|
Mutex m_peers_mutex;
|
||||||
|
|
||||||
ConnectionSendThread m_sendThread;
|
ConnectionSendThread m_sendThread;
|
||||||
ConnectionReceiveThread m_receiveThread;
|
ConnectionReceiveThread m_receiveThread;
|
||||||
|
|
||||||
JMutex m_info_mutex;
|
Mutex m_info_mutex;
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
PeerHandler *m_bc_peerhandler;
|
PeerHandler *m_bc_peerhandler;
|
||||||
|
@ -347,7 +347,7 @@ void ParticleManager::step(float dtime)
|
|||||||
|
|
||||||
void ParticleManager::stepSpawners (float dtime)
|
void ParticleManager::stepSpawners (float dtime)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_spawner_list_lock);
|
MutexAutoLock lock(m_spawner_list_lock);
|
||||||
for(std::map<u32, ParticleSpawner*>::iterator i =
|
for(std::map<u32, ParticleSpawner*>::iterator i =
|
||||||
m_particle_spawners.begin();
|
m_particle_spawners.begin();
|
||||||
i != m_particle_spawners.end();)
|
i != m_particle_spawners.end();)
|
||||||
@ -367,7 +367,7 @@ void ParticleManager::stepSpawners (float dtime)
|
|||||||
|
|
||||||
void ParticleManager::stepParticles (float dtime)
|
void ParticleManager::stepParticles (float dtime)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_particle_list_lock);
|
MutexAutoLock lock(m_particle_list_lock);
|
||||||
for(std::vector<Particle*>::iterator i = m_particles.begin();
|
for(std::vector<Particle*>::iterator i = m_particles.begin();
|
||||||
i != m_particles.end();)
|
i != m_particles.end();)
|
||||||
{
|
{
|
||||||
@ -387,8 +387,8 @@ void ParticleManager::stepParticles (float dtime)
|
|||||||
|
|
||||||
void ParticleManager::clearAll ()
|
void ParticleManager::clearAll ()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_spawner_list_lock);
|
MutexAutoLock lock(m_spawner_list_lock);
|
||||||
JMutexAutoLock lock2(m_particle_list_lock);
|
MutexAutoLock lock2(m_particle_list_lock);
|
||||||
for(std::map<u32, ParticleSpawner*>::iterator i =
|
for(std::map<u32, ParticleSpawner*>::iterator i =
|
||||||
m_particle_spawners.begin();
|
m_particle_spawners.begin();
|
||||||
i != m_particle_spawners.end();)
|
i != m_particle_spawners.end();)
|
||||||
@ -411,7 +411,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
|
|||||||
scene::ISceneManager* smgr, LocalPlayer *player)
|
scene::ISceneManager* smgr, LocalPlayer *player)
|
||||||
{
|
{
|
||||||
if (event->type == CE_DELETE_PARTICLESPAWNER) {
|
if (event->type == CE_DELETE_PARTICLESPAWNER) {
|
||||||
JMutexAutoLock lock(m_spawner_list_lock);
|
MutexAutoLock lock(m_spawner_list_lock);
|
||||||
if (m_particle_spawners.find(event->delete_particlespawner.id) !=
|
if (m_particle_spawners.find(event->delete_particlespawner.id) !=
|
||||||
m_particle_spawners.end())
|
m_particle_spawners.end())
|
||||||
{
|
{
|
||||||
@ -425,7 +425,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
|
|||||||
if (event->type == CE_ADD_PARTICLESPAWNER) {
|
if (event->type == CE_ADD_PARTICLESPAWNER) {
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_spawner_list_lock);
|
MutexAutoLock lock(m_spawner_list_lock);
|
||||||
if (m_particle_spawners.find(event->add_particlespawner.id) !=
|
if (m_particle_spawners.find(event->add_particlespawner.id) !=
|
||||||
m_particle_spawners.end())
|
m_particle_spawners.end())
|
||||||
{
|
{
|
||||||
@ -465,7 +465,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
|
|||||||
delete event->add_particlespawner.maxacc;
|
delete event->add_particlespawner.maxacc;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_spawner_list_lock);
|
MutexAutoLock lock(m_spawner_list_lock);
|
||||||
m_particle_spawners.insert(
|
m_particle_spawners.insert(
|
||||||
std::pair<u32, ParticleSpawner*>(
|
std::pair<u32, ParticleSpawner*>(
|
||||||
event->add_particlespawner.id,
|
event->add_particlespawner.id,
|
||||||
@ -568,6 +568,6 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
|
|||||||
|
|
||||||
void ParticleManager::addParticle(Particle* toadd)
|
void ParticleManager::addParticle(Particle* toadd)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_particle_list_lock);
|
MutexAutoLock lock(m_particle_list_lock);
|
||||||
m_particles.push_back(toadd);
|
m_particles.push_back(toadd);
|
||||||
}
|
}
|
||||||
|
@ -190,8 +190,8 @@ private:
|
|||||||
std::map<u32, ParticleSpawner*> m_particle_spawners;
|
std::map<u32, ParticleSpawner*> m_particle_spawners;
|
||||||
|
|
||||||
ClientEnvironment* m_env;
|
ClientEnvironment* m_env;
|
||||||
JMutex m_particle_list_lock;
|
Mutex m_particle_list_lock;
|
||||||
JMutex m_spawner_list_lock;
|
Mutex m_spawner_list_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "hud.h"
|
#include "hud.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
@ -217,7 +217,7 @@ void Player::deSerialize(std::istream &is, std::string playername)
|
|||||||
|
|
||||||
u32 Player::addHud(HudElement *toadd)
|
u32 Player::addHud(HudElement *toadd)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
u32 id = getFreeHudID();
|
u32 id = getFreeHudID();
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ u32 Player::addHud(HudElement *toadd)
|
|||||||
|
|
||||||
HudElement* Player::getHud(u32 id)
|
HudElement* Player::getHud(u32 id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
if (id < hud.size())
|
if (id < hud.size())
|
||||||
return hud[id];
|
return hud[id];
|
||||||
@ -241,7 +241,7 @@ HudElement* Player::getHud(u32 id)
|
|||||||
|
|
||||||
HudElement* Player::removeHud(u32 id)
|
HudElement* Player::removeHud(u32 id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
HudElement* retval = NULL;
|
HudElement* retval = NULL;
|
||||||
if (id < hud.size()) {
|
if (id < hud.size()) {
|
||||||
@ -253,7 +253,7 @@ HudElement* Player::removeHud(u32 id)
|
|||||||
|
|
||||||
void Player::clearHud()
|
void Player::clearHud()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
while(!hud.empty()) {
|
while(!hud.empty()) {
|
||||||
delete hud.back();
|
delete hud.back();
|
||||||
|
@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
#include "constants.h" // BS
|
#include "constants.h" // BS
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#define PLAYERNAME_SIZE 20
|
#define PLAYERNAME_SIZE 20
|
||||||
@ -413,7 +413,7 @@ private:
|
|||||||
// Protect some critical areas
|
// Protect some critical areas
|
||||||
// hud for example can be modified by EmergeThread
|
// hud for example can be modified by EmergeThread
|
||||||
// and ServerThread
|
// and ServerThread
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
124
src/porting.cpp
124
src/porting.cpp
@ -129,130 +129,6 @@ void signal_handler_init(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Multithreading support
|
|
||||||
*/
|
|
||||||
int getNumberOfProcessors()
|
|
||||||
{
|
|
||||||
#if defined(_SC_NPROCESSORS_ONLN)
|
|
||||||
|
|
||||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
|
||||||
|
|
||||||
#elif defined(__FreeBSD__) || defined(__APPLE__)
|
|
||||||
|
|
||||||
unsigned int len, count;
|
|
||||||
len = sizeof(count);
|
|
||||||
return sysctlbyname("hw.ncpu", &count, &len, NULL, 0);
|
|
||||||
|
|
||||||
#elif defined(_GNU_SOURCE)
|
|
||||||
|
|
||||||
return get_nprocs();
|
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
|
|
||||||
SYSTEM_INFO sysinfo;
|
|
||||||
GetSystemInfo(&sysinfo);
|
|
||||||
return sysinfo.dwNumberOfProcessors;
|
|
||||||
|
|
||||||
#elif defined(PTW32_VERSION) || defined(__hpux)
|
|
||||||
|
|
||||||
return pthread_num_processors_np();
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
bool threadBindToProcessor(threadid_t tid, int pnumber)
|
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid);
|
|
||||||
if (!hThread)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool success = SetThreadAffinityMask(hThread, 1 << pnumber) != 0;
|
|
||||||
|
|
||||||
CloseHandle(hThread);
|
|
||||||
return success;
|
|
||||||
|
|
||||||
#elif (defined(__FreeBSD__) && (__FreeBSD_version >= 702106)) \
|
|
||||||
|| defined(__linux) || defined(linux)
|
|
||||||
|
|
||||||
cpu_set_t cpuset;
|
|
||||||
|
|
||||||
CPU_ZERO(&cpuset);
|
|
||||||
CPU_SET(pnumber, &cpuset);
|
|
||||||
return pthread_setaffinity_np(tid, sizeof(cpuset), &cpuset) == 0;
|
|
||||||
|
|
||||||
#elif defined(__sun) || defined(sun)
|
|
||||||
|
|
||||||
return processor_bind(P_LWPID, MAKE_LWPID_PTHREAD(tid),
|
|
||||||
pnumber, NULL) == 0;
|
|
||||||
|
|
||||||
#elif defined(_AIX)
|
|
||||||
|
|
||||||
return bindprocessor(BINDTHREAD, (tid_t)tid, pnumber) == 0;
|
|
||||||
|
|
||||||
#elif defined(__hpux) || defined(hpux)
|
|
||||||
|
|
||||||
pthread_spu_t answer;
|
|
||||||
|
|
||||||
return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
|
|
||||||
&answer, pnumber, tid) == 0;
|
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
|
|
||||||
struct thread_affinity_policy tapol;
|
|
||||||
|
|
||||||
thread_port_t threadport = pthread_mach_thread_np(tid);
|
|
||||||
tapol.affinity_tag = pnumber + 1;
|
|
||||||
return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
|
|
||||||
(thread_policy_t)&tapol, THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool threadSetPriority(threadid_t tid, int prio)
|
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid);
|
|
||||||
if (!hThread)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool success = SetThreadPriority(hThread, prio) != 0;
|
|
||||||
|
|
||||||
CloseHandle(hThread);
|
|
||||||
return success;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
struct sched_param sparam;
|
|
||||||
int policy;
|
|
||||||
|
|
||||||
if (pthread_getschedparam(tid, &policy, &sparam) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int min = sched_get_priority_min(policy);
|
|
||||||
int max = sched_get_priority_max(policy);
|
|
||||||
|
|
||||||
sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
|
|
||||||
return pthread_setschedparam(tid, policy, &sparam) == 0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Path mangler
|
Path mangler
|
||||||
*/
|
*/
|
||||||
|
@ -64,28 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sched.h>
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
#include <pthread_np.h>
|
|
||||||
typedef cpuset_t cpu_set_t;
|
|
||||||
#elif defined(__sun) || defined(sun)
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/processor.h>
|
|
||||||
#elif defined(_AIX)
|
|
||||||
#include <sys/processor.h>
|
|
||||||
#elif __APPLE__
|
|
||||||
#include <mach/mach_init.h>
|
|
||||||
#include <mach/thread_policy.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define sleep_ms(x) usleep(x*1000)
|
#define sleep_ms(x) usleep(x*1000)
|
||||||
|
|
||||||
#define THREAD_PRIORITY_LOWEST 0
|
|
||||||
#define THREAD_PRIORITY_BELOW_NORMAL 1
|
|
||||||
#define THREAD_PRIORITY_NORMAL 2
|
|
||||||
#define THREAD_PRIORITY_ABOVE_NORMAL 3
|
|
||||||
#define THREAD_PRIORITY_HIGHEST 4
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -165,21 +144,6 @@ std::string getDataPath(const char *subpath);
|
|||||||
*/
|
*/
|
||||||
void initializePaths();
|
void initializePaths();
|
||||||
|
|
||||||
/*
|
|
||||||
Get number of online processors in the system.
|
|
||||||
*/
|
|
||||||
int getNumberOfProcessors();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set a thread's affinity to a particular processor.
|
|
||||||
*/
|
|
||||||
bool threadBindToProcessor(threadid_t tid, int pnumber);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set a thread's priority.
|
|
||||||
*/
|
|
||||||
bool threadSetPriority(threadid_t tid, int prio);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return system information
|
Return system information
|
||||||
e.g. "Linux/3.12.7 x86_64"
|
e.g. "Linux/3.12.7 x86_64"
|
||||||
@ -311,59 +275,6 @@ inline u32 getDeltaMs(u32 old_time_ms, u32 new_time_ms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(linux) || defined(__linux)
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
|
|
||||||
inline void setThreadName(const char *name) {
|
|
||||||
/* It would be cleaner to do this with pthread_setname_np,
|
|
||||||
* which was added to glibc in version 2.12, but some major
|
|
||||||
* distributions are still runing 2.11 and previous versions.
|
|
||||||
*/
|
|
||||||
prctl(PR_SET_NAME, name);
|
|
||||||
}
|
|
||||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <pthread_np.h>
|
|
||||||
|
|
||||||
inline void setThreadName(const char *name) {
|
|
||||||
pthread_set_name_np(pthread_self(), name);
|
|
||||||
}
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
inline void setThreadName(const char *name) {
|
|
||||||
pthread_setname_np(pthread_self(), name);
|
|
||||||
}
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
typedef struct tagTHREADNAME_INFO {
|
|
||||||
DWORD dwType; // must be 0x1000
|
|
||||||
LPCSTR szName; // pointer to name (in user addr space)
|
|
||||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
|
||||||
DWORD dwFlags; // reserved for future use, must be zero
|
|
||||||
} THREADNAME_INFO;
|
|
||||||
|
|
||||||
inline void setThreadName(const char *name) {
|
|
||||||
THREADNAME_INFO info;
|
|
||||||
info.dwType = 0x1000;
|
|
||||||
info.szName = name;
|
|
||||||
info.dwThreadID = -1;
|
|
||||||
info.dwFlags = 0;
|
|
||||||
__try {
|
|
||||||
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *) &info);
|
|
||||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {}
|
|
||||||
}
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
inline void setThreadName(const char *name) {
|
|
||||||
pthread_setname_np(name);
|
|
||||||
}
|
|
||||||
#elif defined(_WIN32) || defined(__GNU__)
|
|
||||||
inline void setThreadName(const char* name) {}
|
|
||||||
#else
|
|
||||||
#warning "Unrecognized platform, thread names will not be available."
|
|
||||||
inline void setThreadName(const char* name) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
float getDisplayDensity();
|
float getDisplayDensity();
|
||||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "porting_android.h"
|
#include "porting_android.h"
|
||||||
|
#include "threading/thread.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -39,30 +40,28 @@ void android_main(android_app *app)
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
porting::app_global = app;
|
porting::app_global = app;
|
||||||
|
|
||||||
porting::setThreadName("MainThread");
|
Thread::setName("MainThread");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
app_dummy();
|
app_dummy();
|
||||||
char *argv[] = { (char*) "minetest" };
|
char *argv[] = {(char*) "minetest"};
|
||||||
main(sizeof(argv) / sizeof(argv[0]), argv);
|
main(sizeof(argv) / sizeof(argv[0]), argv);
|
||||||
}
|
} catch (BaseException &e) {
|
||||||
catch(BaseException e) {
|
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << "Exception handled by main: " << e.what();
|
msg << "Exception handled by main: " << e.what();
|
||||||
const char* message = msg.str().c_str();
|
const char *message = msg.str().c_str();
|
||||||
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME, "%s", message);
|
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME, "%s", message);
|
||||||
errorstream << msg << std::endl;
|
errorstream << msg << std::endl;
|
||||||
retval = -1;
|
retval = -1;
|
||||||
}
|
} catch (...) {
|
||||||
catch(...) {
|
|
||||||
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME,
|
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME,
|
||||||
"Some exception occured");
|
"An unknown exception occured!");
|
||||||
errorstream << "Uncaught exception in main thread!" << std::endl;
|
errorstream << "Uncaught exception in main thread!" << std::endl;
|
||||||
retval = -1;
|
retval = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
porting::cleanupAndroid();
|
porting::cleanupAndroid();
|
||||||
errorstream << "Shutting down minetest." << std::endl;
|
errorstream << "Shutting down." << std::endl;
|
||||||
exit(retval);
|
exit(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "util/timetaker.h"
|
#include "util/timetaker.h"
|
||||||
#include "util/numeric.h" // paging()
|
#include "util/numeric.h" // paging()
|
||||||
#include "debug.h" // assert()
|
#include "debug.h" // assert()
|
||||||
@ -49,7 +49,7 @@ public:
|
|||||||
|
|
||||||
void add(const std::string &name, float value)
|
void add(const std::string &name, float value)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
{
|
{
|
||||||
/* No average shall have been used; mark add used as -2 */
|
/* No average shall have been used; mark add used as -2 */
|
||||||
std::map<std::string, int>::iterator n = m_avgcounts.find(name);
|
std::map<std::string, int>::iterator n = m_avgcounts.find(name);
|
||||||
@ -72,7 +72,7 @@ public:
|
|||||||
|
|
||||||
void avg(const std::string &name, float value)
|
void avg(const std::string &name, float value)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
int &count = m_avgcounts[name];
|
int &count = m_avgcounts[name];
|
||||||
|
|
||||||
assert(count != -2);
|
assert(count != -2);
|
||||||
@ -82,7 +82,7 @@ public:
|
|||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
for(std::map<std::string, float>::iterator
|
for(std::map<std::string, float>::iterator
|
||||||
i = m_data.begin();
|
i = m_data.begin();
|
||||||
i != m_data.end(); ++i)
|
i != m_data.end(); ++i)
|
||||||
@ -114,7 +114,7 @@ public:
|
|||||||
|
|
||||||
void printPage(std::ostream &o, u32 page, u32 pagecount)
|
void printPage(std::ostream &o, u32 page, u32 pagecount)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
u32 minindex, maxindex;
|
u32 minindex, maxindex;
|
||||||
paging(m_data.size(), page, pagecount, minindex, maxindex);
|
paging(m_data.size(), page, pagecount, minindex, maxindex);
|
||||||
@ -159,7 +159,7 @@ public:
|
|||||||
|
|
||||||
void graphAdd(const std::string &id, float value)
|
void graphAdd(const std::string &id, float value)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
std::map<std::string, float>::iterator i =
|
std::map<std::string, float>::iterator i =
|
||||||
m_graphvalues.find(id);
|
m_graphvalues.find(id);
|
||||||
if(i == m_graphvalues.end())
|
if(i == m_graphvalues.end())
|
||||||
@ -169,20 +169,20 @@ public:
|
|||||||
}
|
}
|
||||||
void graphGet(GraphValues &result)
|
void graphGet(GraphValues &result)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
result = m_graphvalues;
|
result = m_graphvalues;
|
||||||
m_graphvalues.clear();
|
m_graphvalues.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(const std::string& name)
|
void remove(const std::string& name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
m_avgcounts.erase(name);
|
m_avgcounts.erase(name);
|
||||||
m_data.erase(name);
|
m_data.erase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
std::map<std::string, float> m_data;
|
std::map<std::string, float> m_data;
|
||||||
std::map<std::string, int> m_avgcounts;
|
std::map<std::string, int> m_avgcounts;
|
||||||
std::map<std::string, float> m_graphvalues;
|
std::map<std::string, float> m_graphvalues;
|
||||||
|
@ -18,8 +18,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "quicktune.h"
|
#include "quicktune.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
std::string QuicktuneValue::getString()
|
std::string QuicktuneValue::getString()
|
||||||
@ -49,12 +49,12 @@ void QuicktuneValue::relativeAdd(float amount)
|
|||||||
|
|
||||||
static std::map<std::string, QuicktuneValue> g_values;
|
static std::map<std::string, QuicktuneValue> g_values;
|
||||||
static std::vector<std::string> g_names;
|
static std::vector<std::string> g_names;
|
||||||
JMutex *g_mutex = NULL;
|
Mutex *g_mutex = NULL;
|
||||||
|
|
||||||
static void makeMutex()
|
static void makeMutex()
|
||||||
{
|
{
|
||||||
if(!g_mutex){
|
if(!g_mutex){
|
||||||
g_mutex = new JMutex();
|
g_mutex = new Mutex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ std::vector<std::string> getQuicktuneNames()
|
|||||||
QuicktuneValue getQuicktuneValue(const std::string &name)
|
QuicktuneValue getQuicktuneValue(const std::string &name)
|
||||||
{
|
{
|
||||||
makeMutex();
|
makeMutex();
|
||||||
JMutexAutoLock lock(*g_mutex);
|
MutexAutoLock lock(*g_mutex);
|
||||||
std::map<std::string, QuicktuneValue>::iterator i = g_values.find(name);
|
std::map<std::string, QuicktuneValue>::iterator i = g_values.find(name);
|
||||||
if(i == g_values.end()){
|
if(i == g_values.end()){
|
||||||
QuicktuneValue val;
|
QuicktuneValue val;
|
||||||
@ -79,7 +79,7 @@ QuicktuneValue getQuicktuneValue(const std::string &name)
|
|||||||
void setQuicktuneValue(const std::string &name, const QuicktuneValue &val)
|
void setQuicktuneValue(const std::string &name, const QuicktuneValue &val)
|
||||||
{
|
{
|
||||||
makeMutex();
|
makeMutex();
|
||||||
JMutexAutoLock lock(*g_mutex);
|
MutexAutoLock lock(*g_mutex);
|
||||||
g_values[name] = val;
|
g_values[name] = val;
|
||||||
g_values[name].modified = true;
|
g_values[name].modified = true;
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ void setQuicktuneValue(const std::string &name, const QuicktuneValue &val)
|
|||||||
void updateQuicktuneValue(const std::string &name, QuicktuneValue &val)
|
void updateQuicktuneValue(const std::string &name, QuicktuneValue &val)
|
||||||
{
|
{
|
||||||
makeMutex();
|
makeMutex();
|
||||||
JMutexAutoLock lock(*g_mutex);
|
MutexAutoLock lock(*g_mutex);
|
||||||
std::map<std::string, QuicktuneValue>::iterator i = g_values.find(name);
|
std::map<std::string, QuicktuneValue>::iterator i = g_values.find(name);
|
||||||
if(i == g_values.end()){
|
if(i == g_values.end()){
|
||||||
g_values[name] = val;
|
g_values[name] = val;
|
||||||
|
@ -47,32 +47,31 @@ AsyncEngine::~AsyncEngine()
|
|||||||
// Request all threads to stop
|
// Request all threads to stop
|
||||||
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
||||||
it != workerThreads.end(); it++) {
|
it != workerThreads.end(); it++) {
|
||||||
(*it)->Stop();
|
(*it)->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Wake up all threads
|
// Wake up all threads
|
||||||
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
||||||
it != workerThreads.end(); it++) {
|
it != workerThreads.end(); it++) {
|
||||||
jobQueueCounter.Post();
|
jobQueueCounter.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for threads to finish
|
// Wait for threads to finish
|
||||||
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
||||||
it != workerThreads.end(); it++) {
|
it != workerThreads.end(); it++) {
|
||||||
(*it)->Wait();
|
(*it)->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force kill all threads
|
// Force kill all threads
|
||||||
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
|
||||||
it != workerThreads.end(); it++) {
|
it != workerThreads.end(); it++) {
|
||||||
(*it)->Kill();
|
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobQueueMutex.Lock();
|
jobQueueMutex.lock();
|
||||||
jobQueue.clear();
|
jobQueue.clear();
|
||||||
jobQueueMutex.Unlock();
|
jobQueueMutex.unlock();
|
||||||
workerThreads.clear();
|
workerThreads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,16 +91,17 @@ void AsyncEngine::initialize(unsigned int numEngines)
|
|||||||
initDone = true;
|
initDone = true;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numEngines; i++) {
|
for (unsigned int i = 0; i < numEngines; i++) {
|
||||||
AsyncWorkerThread *toAdd = new AsyncWorkerThread(this, i);
|
AsyncWorkerThread *toAdd = new AsyncWorkerThread(this,
|
||||||
|
std::string("AsyncWorker-") + itos(i));
|
||||||
workerThreads.push_back(toAdd);
|
workerThreads.push_back(toAdd);
|
||||||
toAdd->Start();
|
toAdd->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
|
unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
|
||||||
{
|
{
|
||||||
jobQueueMutex.Lock();
|
jobQueueMutex.lock();
|
||||||
LuaJobInfo toAdd;
|
LuaJobInfo toAdd;
|
||||||
toAdd.id = jobIdCounter++;
|
toAdd.id = jobIdCounter++;
|
||||||
toAdd.serializedFunction = func;
|
toAdd.serializedFunction = func;
|
||||||
@ -109,9 +109,9 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
|
|||||||
|
|
||||||
jobQueue.push_back(toAdd);
|
jobQueue.push_back(toAdd);
|
||||||
|
|
||||||
jobQueueCounter.Post();
|
jobQueueCounter.post();
|
||||||
|
|
||||||
jobQueueMutex.Unlock();
|
jobQueueMutex.unlock();
|
||||||
|
|
||||||
return toAdd.id;
|
return toAdd.id;
|
||||||
}
|
}
|
||||||
@ -119,8 +119,8 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
LuaJobInfo AsyncEngine::getJob()
|
LuaJobInfo AsyncEngine::getJob()
|
||||||
{
|
{
|
||||||
jobQueueCounter.Wait();
|
jobQueueCounter.wait();
|
||||||
jobQueueMutex.Lock();
|
jobQueueMutex.lock();
|
||||||
|
|
||||||
LuaJobInfo retval;
|
LuaJobInfo retval;
|
||||||
retval.valid = false;
|
retval.valid = false;
|
||||||
@ -130,7 +130,7 @@ LuaJobInfo AsyncEngine::getJob()
|
|||||||
jobQueue.pop_front();
|
jobQueue.pop_front();
|
||||||
retval.valid = true;
|
retval.valid = true;
|
||||||
}
|
}
|
||||||
jobQueueMutex.Unlock();
|
jobQueueMutex.unlock();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -138,16 +138,16 @@ LuaJobInfo AsyncEngine::getJob()
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void AsyncEngine::putJobResult(LuaJobInfo result)
|
void AsyncEngine::putJobResult(LuaJobInfo result)
|
||||||
{
|
{
|
||||||
resultQueueMutex.Lock();
|
resultQueueMutex.lock();
|
||||||
resultQueue.push_back(result);
|
resultQueue.push_back(result);
|
||||||
resultQueueMutex.Unlock();
|
resultQueueMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void AsyncEngine::step(lua_State *L, int errorhandler)
|
void AsyncEngine::step(lua_State *L, int errorhandler)
|
||||||
{
|
{
|
||||||
lua_getglobal(L, "core");
|
lua_getglobal(L, "core");
|
||||||
resultQueueMutex.Lock();
|
resultQueueMutex.lock();
|
||||||
while (!resultQueue.empty()) {
|
while (!resultQueue.empty()) {
|
||||||
LuaJobInfo jobDone = resultQueue.front();
|
LuaJobInfo jobDone = resultQueue.front();
|
||||||
resultQueue.pop_front();
|
resultQueue.pop_front();
|
||||||
@ -166,14 +166,14 @@ void AsyncEngine::step(lua_State *L, int errorhandler)
|
|||||||
|
|
||||||
PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler));
|
PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler));
|
||||||
}
|
}
|
||||||
resultQueueMutex.Unlock();
|
resultQueueMutex.unlock();
|
||||||
lua_pop(L, 1); // Pop core
|
lua_pop(L, 1); // Pop core
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void AsyncEngine::pushFinishedJobs(lua_State* L) {
|
void AsyncEngine::pushFinishedJobs(lua_State* L) {
|
||||||
// Result Table
|
// Result Table
|
||||||
resultQueueMutex.Lock();
|
MutexAutoLock l(resultQueueMutex);
|
||||||
|
|
||||||
unsigned int index = 1;
|
unsigned int index = 1;
|
||||||
lua_createtable(L, resultQueue.size(), 0);
|
lua_createtable(L, resultQueue.size(), 0);
|
||||||
@ -197,8 +197,6 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) {
|
|||||||
|
|
||||||
lua_rawseti(L, top, index++);
|
lua_rawseti(L, top, index++);
|
||||||
}
|
}
|
||||||
|
|
||||||
resultQueueMutex.Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -214,10 +212,10 @@ void AsyncEngine::prepareEnvironment(lua_State* L, int top)
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
|
AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
|
||||||
unsigned int threadNum) :
|
const std::string &name) :
|
||||||
|
Thread(name),
|
||||||
ScriptApiBase(),
|
ScriptApiBase(),
|
||||||
jobDispatcher(jobDispatcher),
|
jobDispatcher(jobDispatcher)
|
||||||
threadnum(threadNum)
|
|
||||||
{
|
{
|
||||||
lua_State *L = getStack();
|
lua_State *L = getStack();
|
||||||
|
|
||||||
@ -235,27 +233,17 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
AsyncWorkerThread::~AsyncWorkerThread()
|
AsyncWorkerThread::~AsyncWorkerThread()
|
||||||
{
|
{
|
||||||
sanity_check(IsRunning() == false);
|
sanity_check(!isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void* AsyncWorkerThread::Thread()
|
void* AsyncWorkerThread::run()
|
||||||
{
|
{
|
||||||
ThreadStarted();
|
|
||||||
|
|
||||||
// Register thread for error logging
|
|
||||||
char number[21];
|
|
||||||
snprintf(number, sizeof(number), "%u", threadnum);
|
|
||||||
log_register_thread(std::string("AsyncWorkerThread_") + number);
|
|
||||||
|
|
||||||
porting::setThreadName((std::string("AsyncWorkTh_") + number).c_str());
|
|
||||||
|
|
||||||
lua_State *L = getStack();
|
lua_State *L = getStack();
|
||||||
|
|
||||||
std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua";
|
std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua";
|
||||||
if (!loadScript(script)) {
|
if (!loadScript(script)) {
|
||||||
errorstream
|
errorstream << "execution of async base environment failed!"
|
||||||
<< "AsyncWorkerThread execution of async base environment failed!"
|
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -267,11 +255,11 @@ void* AsyncWorkerThread::Thread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (!StopRequested()) {
|
while (!stopRequested()) {
|
||||||
// Wait for job
|
// Wait for job
|
||||||
LuaJobInfo toProcess = jobDispatcher->getJob();
|
LuaJobInfo toProcess = jobDispatcher->getJob();
|
||||||
|
|
||||||
if (toProcess.valid == false || StopRequested()) {
|
if (toProcess.valid == false || stopRequested()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,8 +298,6 @@ void* AsyncWorkerThread::Thread()
|
|||||||
|
|
||||||
lua_pop(L, 1); // Pop core
|
lua_pop(L, 1); // Pop core
|
||||||
|
|
||||||
log_deregister_thread();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "jthread/jthread.h"
|
#include "threading/thread.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jsemaphore.h"
|
#include "threading/semaphore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "cpp_api/s_base.h"
|
#include "cpp_api/s_base.h"
|
||||||
@ -52,24 +52,15 @@ struct LuaJobInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Asynchronous working environment
|
// Asynchronous working environment
|
||||||
class AsyncWorkerThread : public JThread, public ScriptApiBase {
|
class AsyncWorkerThread : public Thread, public ScriptApiBase {
|
||||||
public:
|
public:
|
||||||
/**
|
AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name);
|
||||||
* default constructor
|
|
||||||
* @param pointer to job dispatcher
|
|
||||||
*/
|
|
||||||
AsyncWorkerThread(AsyncEngine* jobDispatcher, unsigned int threadNum);
|
|
||||||
|
|
||||||
virtual ~AsyncWorkerThread();
|
virtual ~AsyncWorkerThread();
|
||||||
|
|
||||||
void *Thread();
|
void *run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncEngine *jobDispatcher;
|
AsyncEngine *jobDispatcher;
|
||||||
|
|
||||||
// Thread number. Used for debug output
|
|
||||||
unsigned int threadnum;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Asynchornous thread and job management
|
// Asynchornous thread and job management
|
||||||
@ -148,13 +139,13 @@ private:
|
|||||||
unsigned int jobIdCounter;
|
unsigned int jobIdCounter;
|
||||||
|
|
||||||
// Mutex to protect job queue
|
// Mutex to protect job queue
|
||||||
JMutex jobQueueMutex;
|
Mutex jobQueueMutex;
|
||||||
|
|
||||||
// Job queue
|
// Job queue
|
||||||
std::deque<LuaJobInfo> jobQueue;
|
std::deque<LuaJobInfo> jobQueue;
|
||||||
|
|
||||||
// Mutex to protect result queue
|
// Mutex to protect result queue
|
||||||
JMutex resultQueueMutex;
|
Mutex resultQueueMutex;
|
||||||
// Result queue
|
// Result queue
|
||||||
std::deque<LuaJobInfo> resultQueue;
|
std::deque<LuaJobInfo> resultQueue;
|
||||||
|
|
||||||
@ -162,7 +153,7 @@ private:
|
|||||||
std::vector<AsyncWorkerThread*> workerThreads;
|
std::vector<AsyncWorkerThread*> workerThreads;
|
||||||
|
|
||||||
// Counter semaphore for job dispatching
|
// Counter semaphore for job dispatching
|
||||||
JSemaphore jobQueueCounter;
|
Semaphore jobQueueCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPP_API_ASYNC_EVENTS_HEADER
|
#endif // CPP_API_ASYNC_EVENTS_HEADER
|
||||||
|
@ -28,8 +28,8 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "common/c_types.h"
|
#include "common/c_types.h"
|
||||||
#include "common/c_internal.h"
|
#include "common/c_internal.h"
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ protected:
|
|||||||
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
|
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
|
||||||
void objectrefGet(lua_State *L, u16 id);
|
void objectrefGet(lua_State *L, u16 id);
|
||||||
|
|
||||||
JMutex m_luastackmutex;
|
Mutex m_luastackmutex;
|
||||||
std::string m_last_run_mod;
|
std::string m_last_run_mod;
|
||||||
// Stack index of Lua error handler
|
// Stack index of Lua error handler
|
||||||
int m_errorhandler;
|
int m_errorhandler;
|
||||||
|
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "debug.h" // assert()
|
#include "debug.h" // assert()
|
||||||
class LockChecker {
|
class LockChecker {
|
||||||
public:
|
public:
|
||||||
LockChecker(bool* variable) {
|
LockChecker(bool *variable) {
|
||||||
assert(*variable == false);
|
assert(*variable == false);
|
||||||
|
|
||||||
m_variable = variable;
|
m_variable = variable;
|
||||||
@ -44,7 +44,7 @@ public:
|
|||||||
*m_variable = false;
|
*m_variable = false;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
bool* m_variable;
|
bool *m_variable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRIPTAPI_LOCK_CHECK LockChecker(&(this->m_locked))
|
#define SCRIPTAPI_LOCK_CHECK LockChecker(&(this->m_locked))
|
||||||
@ -53,7 +53,7 @@ bool* m_variable;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SCRIPTAPI_PRECHECKHEADER \
|
#define SCRIPTAPI_PRECHECKHEADER \
|
||||||
JMutexAutoLock(this->m_luastackmutex); \
|
MutexAutoLock(this->m_luastackmutex); \
|
||||||
SCRIPTAPI_LOCK_CHECK; \
|
SCRIPTAPI_LOCK_CHECK; \
|
||||||
realityCheck(); \
|
realityCheck(); \
|
||||||
lua_State *L = getStack(); \
|
lua_State *L = getStack(); \
|
||||||
|
106
src/server.cpp
106
src/server.cpp
@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "ban.h"
|
#include "ban.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -71,35 +71,29 @@ public:
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ServerThread : public JThread
|
class ServerThread : public Thread
|
||||||
{
|
{
|
||||||
Server *m_server;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ServerThread(Server *server):
|
ServerThread(Server *server):
|
||||||
JThread(),
|
Thread("Server"),
|
||||||
m_server(server)
|
m_server(server)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void * Thread();
|
void *run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Server *m_server;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *ServerThread::Thread()
|
void *ServerThread::run()
|
||||||
{
|
{
|
||||||
log_register_thread("ServerThread");
|
|
||||||
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
|
|
||||||
m_server->AsyncRunStep(true);
|
m_server->AsyncRunStep(true);
|
||||||
|
|
||||||
ThreadStarted();
|
while (!stopRequested()) {
|
||||||
|
|
||||||
porting::setThreadName("ServerThread");
|
|
||||||
|
|
||||||
while (!StopRequested()) {
|
|
||||||
try {
|
try {
|
||||||
//TimeTaker timer("AsyncRunStep() + Receive()");
|
//TimeTaker timer("AsyncRunStep() + Receive()");
|
||||||
|
|
||||||
@ -267,8 +261,8 @@ Server::Server(
|
|||||||
errorstream << std::endl;
|
errorstream << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock environment
|
//lock environment
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
|
|
||||||
// Load mapgen params from Settings
|
// Load mapgen params from Settings
|
||||||
m_emerge->loadMapgenParams();
|
m_emerge->loadMapgenParams();
|
||||||
@ -379,7 +373,7 @@ Server::~Server()
|
|||||||
SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
|
SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
|
|
||||||
// Execute script shutdown hooks
|
// Execute script shutdown hooks
|
||||||
m_script->on_shutdown();
|
m_script->on_shutdown();
|
||||||
@ -447,14 +441,14 @@ void Server::start(Address bind_addr)
|
|||||||
<< bind_addr.serializeString() <<"..."<<std::endl;
|
<< bind_addr.serializeString() <<"..."<<std::endl;
|
||||||
|
|
||||||
// Stop thread if already running
|
// Stop thread if already running
|
||||||
m_thread->Stop();
|
m_thread->stop();
|
||||||
|
|
||||||
// Initialize connection
|
// Initialize connection
|
||||||
m_con.SetTimeoutMs(30);
|
m_con.SetTimeoutMs(30);
|
||||||
m_con.Serve(bind_addr);
|
m_con.Serve(bind_addr);
|
||||||
|
|
||||||
// Start thread
|
// Start thread
|
||||||
m_thread->Start();
|
m_thread->start();
|
||||||
|
|
||||||
// ASCII art for the win!
|
// ASCII art for the win!
|
||||||
actionstream
|
actionstream
|
||||||
@ -477,9 +471,9 @@ void Server::stop()
|
|||||||
infostream<<"Server: Stopping and waiting threads"<<std::endl;
|
infostream<<"Server: Stopping and waiting threads"<<std::endl;
|
||||||
|
|
||||||
// Stop threads (set run=false first so both start stopping)
|
// Stop threads (set run=false first so both start stopping)
|
||||||
m_thread->Stop();
|
m_thread->stop();
|
||||||
//m_emergethread.setRun(false);
|
//m_emergethread.setRun(false);
|
||||||
m_thread->Wait();
|
m_thread->wait();
|
||||||
//m_emergethread.stop();
|
//m_emergethread.stop();
|
||||||
|
|
||||||
infostream<<"Server: Threads stopped"<<std::endl;
|
infostream<<"Server: Threads stopped"<<std::endl;
|
||||||
@ -492,7 +486,7 @@ void Server::step(float dtime)
|
|||||||
if(dtime > 2.0)
|
if(dtime > 2.0)
|
||||||
dtime = 2.0;
|
dtime = 2.0;
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_step_dtime_mutex);
|
MutexAutoLock lock(m_step_dtime_mutex);
|
||||||
m_step_dtime += dtime;
|
m_step_dtime += dtime;
|
||||||
}
|
}
|
||||||
// Throw if fatal error occurred in thread
|
// Throw if fatal error occurred in thread
|
||||||
@ -521,7 +515,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
|
|
||||||
float dtime;
|
float dtime;
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock1(m_step_dtime_mutex);
|
MutexAutoLock lock1(m_step_dtime_mutex);
|
||||||
dtime = m_step_dtime;
|
dtime = m_step_dtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +533,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
//infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
|
//infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock1(m_step_dtime_mutex);
|
MutexAutoLock lock1(m_step_dtime_mutex);
|
||||||
m_step_dtime -= dtime;
|
m_step_dtime -= dtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +564,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
MutexAutoLock lock(m_env_mutex);
|
||||||
// Figure out and report maximum lag to environment
|
// Figure out and report maximum lag to environment
|
||||||
float max_lag = m_env->getMaxLagEstimate();
|
float max_lag = m_env->getMaxLagEstimate();
|
||||||
max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
|
max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
|
||||||
@ -590,7 +584,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
static const float map_timer_and_unload_dtime = 2.92;
|
static const float map_timer_and_unload_dtime = 2.92;
|
||||||
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
|
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
MutexAutoLock lock(m_env_mutex);
|
||||||
// Run Map's timers and unload unused data
|
// Run Map's timers and unload unused data
|
||||||
ScopeProfiler sp(g_profiler, "Server: map timer and unload");
|
ScopeProfiler sp(g_profiler, "Server: map timer and unload");
|
||||||
m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
|
m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
|
||||||
@ -608,7 +602,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
{
|
{
|
||||||
m_liquid_transform_timer -= m_liquid_transform_every;
|
m_liquid_transform_timer -= m_liquid_transform_every;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
MutexAutoLock lock(m_env_mutex);
|
||||||
|
|
||||||
ScopeProfiler sp(g_profiler, "Server: liquid transform");
|
ScopeProfiler sp(g_profiler, "Server: liquid transform");
|
||||||
|
|
||||||
@ -669,9 +663,9 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
//infostream<<"Server: Checking added and deleted active objects"<<std::endl;
|
//infostream<<"Server: Checking added and deleted active objects"<<std::endl;
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
|
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
std::map<u16, RemoteClient*> clients = m_clients.getClientList();
|
std::map<u16, RemoteClient*> clients = m_clients.getClientList();
|
||||||
ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
|
ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
|
||||||
|
|
||||||
@ -792,14 +786,14 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
<< added_objects.size() << " added, "
|
<< added_objects.size() << " added, "
|
||||||
<< "packet size is " << pktSize << std::endl;
|
<< "packet size is " << pktSize << std::endl;
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send object messages
|
Send object messages
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
||||||
|
|
||||||
// Key = object id
|
// Key = object id
|
||||||
@ -825,7 +819,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
message_list->push_back(aom);
|
message_list->push_back(aom);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
std::map<u16, RemoteClient*> clients = m_clients.getClientList();
|
std::map<u16, RemoteClient*> clients = m_clients.getClientList();
|
||||||
// Route data to every client
|
// Route data to every client
|
||||||
for (std::map<u16, RemoteClient*>::iterator
|
for (std::map<u16, RemoteClient*>::iterator
|
||||||
@ -876,7 +870,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
SendActiveObjectMessages(client->peer_id, unreliable_data, false);
|
SendActiveObjectMessages(client->peer_id, unreliable_data, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
|
|
||||||
// Clear buffered_messages
|
// Clear buffered_messages
|
||||||
for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
|
for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
|
||||||
@ -891,7 +885,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
// We will be accessing the environment
|
// We will be accessing the environment
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
MutexAutoLock lock(m_env_mutex);
|
||||||
|
|
||||||
// Don't send too many at a time
|
// Don't send too many at a time
|
||||||
//u32 count = 0;
|
//u32 count = 0;
|
||||||
@ -1012,7 +1006,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||||||
if(counter >= g_settings->getFloat("server_map_save_interval"))
|
if(counter >= g_settings->getFloat("server_map_save_interval"))
|
||||||
{
|
{
|
||||||
counter = 0.0;
|
counter = 0.0;
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
MutexAutoLock lock(m_env_mutex);
|
||||||
|
|
||||||
ScopeProfiler sp(g_profiler, "Server: saving stuff");
|
ScopeProfiler sp(g_profiler, "Server: saving stuff");
|
||||||
|
|
||||||
@ -1068,7 +1062,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
|
|||||||
{
|
{
|
||||||
std::string playername = "";
|
std::string playername = "";
|
||||||
PlayerSAO *playersao = NULL;
|
PlayerSAO *playersao = NULL;
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
try {
|
try {
|
||||||
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
|
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
|
||||||
if (client != NULL) {
|
if (client != NULL) {
|
||||||
@ -1076,10 +1070,10 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
|
|||||||
playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
|
playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
|
||||||
}
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
|
|
||||||
RemotePlayer *player =
|
RemotePlayer *player =
|
||||||
static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
|
static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
|
||||||
@ -1174,7 +1168,7 @@ void Server::ProcessData(NetworkPacket *pkt)
|
|||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
// Environment is locked first.
|
// Environment is locked first.
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
|
|
||||||
ScopeProfiler sp(g_profiler, "Server::ProcessData");
|
ScopeProfiler sp(g_profiler, "Server::ProcessData");
|
||||||
u32 peer_id = pkt->getPeerId();
|
u32 peer_id = pkt->getPeerId();
|
||||||
@ -1356,14 +1350,14 @@ void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
|
|||||||
void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
|
void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
|
||||||
{
|
{
|
||||||
std::vector<u16> clients = m_clients.getClientIDs();
|
std::vector<u16> clients = m_clients.getClientIDs();
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
// Set the modified blocks unsent for all the clients
|
// Set the modified blocks unsent for all the clients
|
||||||
for (std::vector<u16>::iterator i = clients.begin();
|
for (std::vector<u16>::iterator i = clients.begin();
|
||||||
i != clients.end(); ++i) {
|
i != clients.end(); ++i) {
|
||||||
if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
|
if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
|
||||||
client->SetBlocksNotSent(block);
|
client->SetBlocksNotSent(block);
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::peerAdded(con::Peer *peer)
|
void Server::peerAdded(con::Peer *peer)
|
||||||
@ -1413,11 +1407,11 @@ bool Server::getClientInfo(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
*state = m_clients.getClientState(peer_id);
|
*state = m_clients.getClientState(peer_id);
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
|
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
|
||||||
|
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,7 +1424,7 @@ bool Server::getClientInfo(
|
|||||||
*patch = client->getPatch();
|
*patch = client->getPatch();
|
||||||
*vers_string = client->getPatch();
|
*vers_string = client->getPatch();
|
||||||
|
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2098,7 +2092,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
|
NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
|
RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
|
||||||
if (client != 0) {
|
if (client != 0) {
|
||||||
pkt << p << n.param0 << n.param1 << n.param2
|
pkt << p << n.param0 << n.param1 << n.param2
|
||||||
@ -2112,7 +2106,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
|
|
||||||
// Send as reliable
|
// Send as reliable
|
||||||
if (pkt.getSize() > 0)
|
if (pkt.getSize() > 0)
|
||||||
@ -2123,13 +2117,13 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
|
|||||||
void Server::setBlockNotSent(v3s16 p)
|
void Server::setBlockNotSent(v3s16 p)
|
||||||
{
|
{
|
||||||
std::vector<u16> clients = m_clients.getClientIDs();
|
std::vector<u16> clients = m_clients.getClientIDs();
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
for(std::vector<u16>::iterator i = clients.begin();
|
for(std::vector<u16>::iterator i = clients.begin();
|
||||||
i != clients.end(); ++i) {
|
i != clients.end(); ++i) {
|
||||||
RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
|
RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
|
||||||
client->SetBlockNotSent(p);
|
client->SetBlockNotSent(p);
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
|
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
|
||||||
@ -2158,7 +2152,7 @@ void Server::SendBlocks(float dtime)
|
|||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
MutexAutoLock envlock(m_env_mutex);
|
||||||
//TODO check if one big lock could be faster then multiple small ones
|
//TODO check if one big lock could be faster then multiple small ones
|
||||||
|
|
||||||
ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
|
ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
|
||||||
@ -2172,7 +2166,7 @@ void Server::SendBlocks(float dtime)
|
|||||||
|
|
||||||
std::vector<u16> clients = m_clients.getClientIDs();
|
std::vector<u16> clients = m_clients.getClientIDs();
|
||||||
|
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
for(std::vector<u16>::iterator i = clients.begin();
|
for(std::vector<u16>::iterator i = clients.begin();
|
||||||
i != clients.end(); ++i) {
|
i != clients.end(); ++i) {
|
||||||
RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
|
RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
|
||||||
@ -2183,7 +2177,7 @@ void Server::SendBlocks(float dtime)
|
|||||||
total_sending += client->SendingCount();
|
total_sending += client->SendingCount();
|
||||||
client->GetNextBlocks(m_env,m_emerge, dtime, queue);
|
client->GetNextBlocks(m_env,m_emerge, dtime, queue);
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort.
|
// Sort.
|
||||||
@ -2191,7 +2185,7 @@ void Server::SendBlocks(float dtime)
|
|||||||
// Lowest is most important.
|
// Lowest is most important.
|
||||||
std::sort(queue.begin(), queue.end());
|
std::sort(queue.begin(), queue.end());
|
||||||
|
|
||||||
m_clients.Lock();
|
m_clients.lock();
|
||||||
for(u32 i=0; i<queue.size(); i++)
|
for(u32 i=0; i<queue.size(); i++)
|
||||||
{
|
{
|
||||||
//TODO: Calculate limit dynamically
|
//TODO: Calculate limit dynamically
|
||||||
@ -2221,7 +2215,7 @@ void Server::SendBlocks(float dtime)
|
|||||||
client->SentBlock(q.pos);
|
client->SentBlock(q.pos);
|
||||||
total_sending++;
|
total_sending++;
|
||||||
}
|
}
|
||||||
m_clients.Unlock();
|
m_clients.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::fillMediaCache()
|
void Server::fillMediaCache()
|
||||||
@ -2702,7 +2696,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
JMutexAutoLock env_lock(m_env_mutex);
|
MutexAutoLock env_lock(m_env_mutex);
|
||||||
m_clients.DeleteClient(peer_id);
|
m_clients.DeleteClient(peer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,7 @@ private:
|
|||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
ServerEnvironment *m_env;
|
ServerEnvironment *m_env;
|
||||||
JMutex m_env_mutex;
|
Mutex m_env_mutex;
|
||||||
|
|
||||||
// server connection
|
// server connection
|
||||||
con::Connection m_con;
|
con::Connection m_con;
|
||||||
@ -557,7 +557,7 @@ private:
|
|||||||
// A buffer for time steps
|
// A buffer for time steps
|
||||||
// step() increments and AsyncRunStep() run by m_thread reads it.
|
// step() increments and AsyncRunStep() run by m_thread reads it.
|
||||||
float m_step_dtime;
|
float m_step_dtime;
|
||||||
JMutex m_step_dtime_mutex;
|
Mutex m_step_dtime_mutex;
|
||||||
|
|
||||||
// current server step lag counter
|
// current server step lag counter
|
||||||
float m_lag;
|
float m_lag;
|
||||||
|
@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "jthread/jmutexautolock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "strfnd.h"
|
#include "strfnd.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -56,8 +56,8 @@ Settings & Settings::operator = (const Settings &other)
|
|||||||
if (&other == this)
|
if (&other == this)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
JMutexAutoLock lock2(other.m_mutex);
|
MutexAutoLock lock2(other.m_mutex);
|
||||||
|
|
||||||
clearNoLock();
|
clearNoLock();
|
||||||
updateNoLock(other);
|
updateNoLock(other);
|
||||||
@ -155,7 +155,7 @@ bool Settings::readConfigFile(const char *filename)
|
|||||||
|
|
||||||
bool Settings::parseConfigLines(std::istream &is, const std::string &end)
|
bool Settings::parseConfigLines(std::istream &is, const std::string &end)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
std::string line, name, value;
|
std::string line, name, value;
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end)
|
|||||||
|
|
||||||
void Settings::writeLines(std::ostream &os, u32 tab_depth) const
|
void Settings::writeLines(std::ostream &os, u32 tab_depth) const
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
for (std::map<std::string, SettingsEntry>::const_iterator
|
for (std::map<std::string, SettingsEntry>::const_iterator
|
||||||
it = m_settings.begin();
|
it = m_settings.begin();
|
||||||
@ -298,7 +298,7 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os,
|
|||||||
|
|
||||||
bool Settings::updateConfigFile(const char *filename)
|
bool Settings::updateConfigFile(const char *filename)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
std::ifstream is(filename);
|
std::ifstream is(filename);
|
||||||
std::ostringstream os(std::ios_base::binary);
|
std::ostringstream os(std::ios_base::binary);
|
||||||
@ -379,7 +379,7 @@ bool Settings::parseCommandLine(int argc, char *argv[],
|
|||||||
|
|
||||||
const SettingsEntry &Settings::getEntry(const std::string &name) const
|
const SettingsEntry &Settings::getEntry(const std::string &name) const
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
std::map<std::string, SettingsEntry>::const_iterator n;
|
std::map<std::string, SettingsEntry>::const_iterator n;
|
||||||
if ((n = m_settings.find(name)) == m_settings.end()) {
|
if ((n = m_settings.find(name)) == m_settings.end()) {
|
||||||
@ -562,7 +562,7 @@ bool Settings::getNoiseParamsFromGroup(const std::string &name,
|
|||||||
|
|
||||||
bool Settings::exists(const std::string &name) const
|
bool Settings::exists(const std::string &name) const
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
return (m_settings.find(name) != m_settings.end() ||
|
return (m_settings.find(name) != m_settings.end() ||
|
||||||
m_defaults.find(name) != m_defaults.end());
|
m_defaults.find(name) != m_defaults.end());
|
||||||
@ -742,7 +742,7 @@ bool Settings::setEntry(const std::string &name, const void *data,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name];
|
SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name];
|
||||||
old_group = entry.group;
|
old_group = entry.group;
|
||||||
@ -878,7 +878,7 @@ bool Settings::setNoiseParams(const std::string &name,
|
|||||||
|
|
||||||
bool Settings::remove(const std::string &name)
|
bool Settings::remove(const std::string &name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
delete m_settings[name].group;
|
delete m_settings[name].group;
|
||||||
return m_settings.erase(name);
|
return m_settings.erase(name);
|
||||||
@ -887,13 +887,13 @@ bool Settings::remove(const std::string &name)
|
|||||||
|
|
||||||
void Settings::clear()
|
void Settings::clear()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
clearNoLock();
|
clearNoLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::clearDefaults()
|
void Settings::clearDefaults()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
clearDefaultsNoLock();
|
clearDefaultsNoLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,7 +902,7 @@ void Settings::updateValue(const Settings &other, const std::string &name)
|
|||||||
if (&other == this)
|
if (&other == this)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string val = other.get(name);
|
std::string val = other.get(name);
|
||||||
@ -918,8 +918,8 @@ void Settings::update(const Settings &other)
|
|||||||
if (&other == this)
|
if (&other == this)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
JMutexAutoLock lock2(other.m_mutex);
|
MutexAutoLock lock2(other.m_mutex);
|
||||||
|
|
||||||
updateNoLock(other);
|
updateNoLock(other);
|
||||||
}
|
}
|
||||||
@ -982,13 +982,13 @@ void Settings::clearDefaultsNoLock()
|
|||||||
void Settings::registerChangedCallback(std::string name,
|
void Settings::registerChangedCallback(std::string name,
|
||||||
setting_changed_callback cbf, void *userdata)
|
setting_changed_callback cbf, void *userdata)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_callbackMutex);
|
MutexAutoLock lock(m_callbackMutex);
|
||||||
m_callbacks[name].push_back(std::make_pair(cbf, userdata));
|
m_callbacks[name].push_back(std::make_pair(cbf, userdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata)
|
void Settings::deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_callbackMutex);
|
MutexAutoLock lock(m_callbackMutex);
|
||||||
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
|
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
|
||||||
if (iterToVector != m_callbacks.end())
|
if (iterToVector != m_callbacks.end())
|
||||||
{
|
{
|
||||||
@ -1004,7 +1004,7 @@ void Settings::deregisterChangedCallback(std::string name, setting_changed_callb
|
|||||||
|
|
||||||
void Settings::doCallbacks(const std::string name)
|
void Settings::doCallbacks(const std::string name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_callbackMutex);
|
MutexAutoLock lock(m_callbackMutex);
|
||||||
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
|
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
|
||||||
if (iterToVector != m_callbacks.end())
|
if (iterToVector != m_callbacks.end())
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -225,8 +225,8 @@ private:
|
|||||||
|
|
||||||
std::map<std::string, std::vector<std::pair<setting_changed_callback,void*> > > m_callbacks;
|
std::map<std::string, std::vector<std::pair<setting_changed_callback,void*> > > m_callbacks;
|
||||||
|
|
||||||
mutable JMutex m_callbackMutex;
|
mutable Mutex m_callbackMutex;
|
||||||
mutable JMutex m_mutex; // All methods that access m_settings/m_defaults directly should lock this.
|
mutable Mutex m_mutex; // All methods that access m_settings/m_defaults directly should lock this.
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ private:
|
|||||||
// The first position contains a dummy shader.
|
// The first position contains a dummy shader.
|
||||||
std::vector<ShaderInfo> m_shaderinfo_cache;
|
std::vector<ShaderInfo> m_shaderinfo_cache;
|
||||||
// The former container is behind this mutex
|
// The former container is behind this mutex
|
||||||
JMutex m_shaderinfo_cache_mutex;
|
Mutex m_shaderinfo_cache_mutex;
|
||||||
|
|
||||||
// Queued shader fetches (to be processed by the main thread)
|
// Queued shader fetches (to be processed by the main thread)
|
||||||
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
|
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
|
||||||
@ -469,7 +469,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
|||||||
Add shader to caches (add dummy shaders too)
|
Add shader to caches (add dummy shaders too)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
|
|
||||||
u32 id = m_shaderinfo_cache.size();
|
u32 id = m_shaderinfo_cache.size();
|
||||||
m_shaderinfo_cache.push_back(info);
|
m_shaderinfo_cache.push_back(info);
|
||||||
@ -483,7 +483,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
|||||||
|
|
||||||
ShaderInfo ShaderSource::getShaderInfo(u32 id)
|
ShaderInfo ShaderSource::getShaderInfo(u32 id)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
|
|
||||||
if(id >= m_shaderinfo_cache.size())
|
if(id >= m_shaderinfo_cache.size())
|
||||||
return ShaderInfo();
|
return ShaderInfo();
|
||||||
@ -511,7 +511,7 @@ void ShaderSource::insertSourceShader(const std::string &name_of_shader,
|
|||||||
|
|
||||||
void ShaderSource::rebuildShaders()
|
void ShaderSource::rebuildShaders()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
|
|
||||||
/*// Oh well... just clear everything, they'll load sometime.
|
/*// Oh well... just clear everything, they'll load sometime.
|
||||||
m_shaderinfo_cache.clear();
|
m_shaderinfo_cache.clear();
|
||||||
|
6
src/threading/CMakeLists.txt
Normal file
6
src/threading/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
set(JTHREAD_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mutex.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp
|
||||||
|
PARENT_SCOPE)
|
||||||
|
|
96
src/threading/atomic.h
Normal file
96
src/threading/atomic.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2015 ShadowNinja <shadowninja@minetest.net>
|
||||||
|
|
||||||
|
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 THREADING_ATOMIC_H
|
||||||
|
#define THREADING_ATOMIC_H
|
||||||
|
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#include <atomic>
|
||||||
|
template<typename T> using Atomic = std::atomic<T>;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||||
|
#define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
||||||
|
#if GCC_VERSION >= 407 || CLANG_VERSION >= 302
|
||||||
|
#define ATOMIC_LOAD(T, v) return __atomic_load_n(&(v), __ATOMIC_SEQ_CST)
|
||||||
|
#define ATOMIC_STORE(T, v, x) __atomic_store (&(v), &(x), __ATOMIC_SEQ_CST); return x
|
||||||
|
#define ATOMIC_ADD_EQ(T, v, x) return __atomic_add_fetch(&(v), (x), __ATOMIC_SEQ_CST)
|
||||||
|
#define ATOMIC_SUB_EQ(T, v, x) return __atomic_sub_fetch(&(v), (x), __ATOMIC_SEQ_CST)
|
||||||
|
#define ATOMIC_POST_INC(T, v) return __atomic_fetch_add(&(v), 1, __ATOMIC_SEQ_CST)
|
||||||
|
#define ATOMIC_POST_DEC(T, v) return __atomic_fetch_sub(&(v), 1, __ATOMIC_SEQ_CST)
|
||||||
|
#else
|
||||||
|
#define ATOMIC_USE_LOCK
|
||||||
|
#include "threading/mutex.h"
|
||||||
|
|
||||||
|
#define ATOMIC_LOCK_OP(T, op) do { \
|
||||||
|
mutex.lock(); \
|
||||||
|
T _val = (op); \
|
||||||
|
mutex.unlock(); \
|
||||||
|
return _val; \
|
||||||
|
} while (0)
|
||||||
|
#define ATOMIC_LOAD(T, v) \
|
||||||
|
if (sizeof(T) <= sizeof(void*)) return v; \
|
||||||
|
else ATOMIC_LOCK_OP(T, v);
|
||||||
|
#define ATOMIC_STORE(T, v, x) \
|
||||||
|
if (sizeof(T) <= sizeof(void*)) return v = x; \
|
||||||
|
else ATOMIC_LOCK_OP(T, v = x);
|
||||||
|
# if GCC_VERSION >= 401
|
||||||
|
#define ATOMIC_ADD_EQ(T, v, x) return __sync_add_and_fetch(&(v), (x))
|
||||||
|
#define ATOMIC_SUB_EQ(T, v, x) return __sync_sub_and_fetch(&(v), (x))
|
||||||
|
#define ATOMIC_POST_INC(T, v) return __sync_fetch_and_add(&(v), 1)
|
||||||
|
#define ATOMIC_POST_DEC(T, v) return __sync_fetch_and_sub(&(v), 1)
|
||||||
|
# else
|
||||||
|
#define ATOMIC_ADD_EQ(T, v, x) ATOMIC_LOCK_OP(T, v += x)
|
||||||
|
#define ATOMIC_SUB_EQ(T, v, x) ATOMIC_LOCK_OP(T, v -= x)
|
||||||
|
#define ATOMIC_POST_INC(T, v) ATOMIC_LOCK_OP(T, v++)
|
||||||
|
#define ATOMIC_POST_DEC(T, v) ATOMIC_LOCK_OP(T, v--)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Atomic
|
||||||
|
{
|
||||||
|
// Like C++11 std::enable_if, but defaults to char since C++03 doesn't support SFINAE
|
||||||
|
template<bool B, typename T_ = void> struct enable_if { typedef char type; };
|
||||||
|
template<typename T_> struct enable_if<true, T_> { typedef T_ type; };
|
||||||
|
public:
|
||||||
|
Atomic(const T &v=0) : val(v) {}
|
||||||
|
|
||||||
|
operator T () { ATOMIC_LOAD(T, val); }
|
||||||
|
T operator = (T x) { ATOMIC_STORE(T, val, x); }
|
||||||
|
T operator += (T x) { ATOMIC_ADD_EQ(T, val, x); }
|
||||||
|
T operator -= (T x) { ATOMIC_SUB_EQ(T, val, x); }
|
||||||
|
T operator ++ () { return *this += 1; }
|
||||||
|
T operator -- () { return *this -= 1; }
|
||||||
|
T operator ++ (int) { ATOMIC_POST_INC(T, val); }
|
||||||
|
T operator -- (int) { ATOMIC_POST_DEC(T, val); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile T val;
|
||||||
|
#ifdef ATOMIC_USE_LOCK
|
||||||
|
typename enable_if<sizeof(T) <= sizeof(void*), Mutex>::type mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // C++11
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
57
src/threading/event.h
Normal file
57
src/threading/event.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREADING_EVENT_H
|
||||||
|
#define THREADING_EVENT_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include "threading/semaphore.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
public:
|
||||||
|
#ifdef _WIN32
|
||||||
|
Event() { event = CreateEvent(NULL, false, false, NULL); }
|
||||||
|
~Event() { CloseHandle(event); }
|
||||||
|
void wait() { WaitForSingleObject(event, INFINITE); }
|
||||||
|
void signal() { SetEvent(event); }
|
||||||
|
#else
|
||||||
|
void wait() { sem.wait(); }
|
||||||
|
void signal() { sem.post(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE event;
|
||||||
|
#else
|
||||||
|
Semaphore sem;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
83
src/threading/mutex.cpp
Normal file
83
src/threading/mutex.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Windows std::mutex is much slower than the critical section API
|
||||||
|
#if __cplusplus < 201103L || defined(_WIN32)
|
||||||
|
|
||||||
|
#include "threading/mutex.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <cassert>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
Mutex::Mutex()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
InitializeCriticalSection(&mutex);
|
||||||
|
#else
|
||||||
|
int ret = pthread_mutex_init(&mutex, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex::~Mutex()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
DeleteCriticalSection(&mutex);
|
||||||
|
#else
|
||||||
|
int ret = pthread_mutex_destroy(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mutex::lock()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
EnterCriticalSection(&mutex);
|
||||||
|
#else
|
||||||
|
int ret = pthread_mutex_lock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mutex::unlock()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
LeaveCriticalSection(&mutex);
|
||||||
|
#else
|
||||||
|
int ret = pthread_mutex_unlock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
66
src/threading/mutex.h
Normal file
66
src/threading/mutex.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREADING_MUTEX_H
|
||||||
|
#define THREADING_MUTEX_H
|
||||||
|
|
||||||
|
// Windows std::mutex is much slower than the critical section API
|
||||||
|
#if __cplusplus >= 201103L && !defined(_WIN32)
|
||||||
|
#include <mutex>
|
||||||
|
using Mutex = std::mutex;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#endif
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#else // pthread
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Mutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mutex();
|
||||||
|
~Mutex();
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef _WIN32
|
||||||
|
CRITICAL_SECTION mutex;
|
||||||
|
#else // pthread
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // C++11
|
||||||
|
|
||||||
|
#endif
|
@ -1,4 +1,8 @@
|
|||||||
The license of JThread:
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
@ -7,14 +11,40 @@ the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|||||||
and/or sell copies of the Software, and to permit persons to whom the
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
Software is furnished to do so, subject to the following conditions:
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
The above copyright notice and this permission notice shall be included in
|
||||||
in all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREADING_MUTEX_AUTO_LOCK_H
|
||||||
|
#define THREADING_MUTEX_AUTO_LOCK_H
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#include <mutex>
|
||||||
|
using MutexAutoLock = std::lock_guard<std::mutex>;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "threading/mutex.h"
|
||||||
|
|
||||||
|
|
||||||
|
class MutexAutoLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MutexAutoLock(Mutex &m) : mutex(m) { mutex.lock(); }
|
||||||
|
~MutexAutoLock() { mutex.unlock(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mutex &mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
161
src/threading/semaphore.cpp
Normal file
161
src/threading/semaphore.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2013 sapier <sapier AT gmx DOT net>
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "threading/semaphore.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define MAX_SEMAPHORE_COUNT LONG_MAX - 1
|
||||||
|
#else
|
||||||
|
#include <cerrno>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <mach/task.h>
|
||||||
|
#include <mach/semaphore.h>
|
||||||
|
#include <sys/semaphore.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#undef sem_t
|
||||||
|
#undef sem_init
|
||||||
|
#undef sem_wait
|
||||||
|
#undef sem_post
|
||||||
|
#undef sem_destroy
|
||||||
|
#define sem_t semaphore_t
|
||||||
|
#define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
|
||||||
|
#define sem_wait(s) semaphore_wait(*(s))
|
||||||
|
#define sem_post(s) semaphore_signal(*(s))
|
||||||
|
#define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Semaphore::Semaphore(int val)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
semaphore = CreateSemaphore(NULL, val, MAX_SEMAPHORE_COUNT, NULL);
|
||||||
|
#else
|
||||||
|
int ret = sem_init(&semaphore, 0, val);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Semaphore::~Semaphore()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
CloseHandle(semaphore);
|
||||||
|
#else
|
||||||
|
int ret = sem_destroy(&semaphore);
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
// Workaround for broken bionic semaphore implementation!
|
||||||
|
assert(!ret || errno == EBUSY);
|
||||||
|
#else
|
||||||
|
assert(!ret);
|
||||||
|
#endif
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Semaphore::post(unsigned int num)
|
||||||
|
{
|
||||||
|
assert(num > 0);
|
||||||
|
#ifdef _WIN32
|
||||||
|
ReleaseSemaphore(semaphore, num, NULL);
|
||||||
|
#else
|
||||||
|
for (unsigned i = 0; i < num; i++) {
|
||||||
|
int ret = sem_post(&semaphore);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Semaphore::wait()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
WaitForSingleObject(semaphore, INFINITE);
|
||||||
|
#else
|
||||||
|
int ret = sem_wait(&semaphore);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Semaphore::wait(unsigned int time_ms)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
unsigned int ret = WaitForSingleObject(semaphore, time_ms);
|
||||||
|
|
||||||
|
if (ret == WAIT_OBJECT_0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
assert(ret == WAIT_TIMEOUT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
mach_timespec_t wait_time;
|
||||||
|
wait_time.tv_sec = time_ms / 1000;
|
||||||
|
wait_time.tv_nsec = 1000000 * (time_ms % 1000);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
int ret = semaphore_timedwait(semaphore, wait_time);
|
||||||
|
switch (ret) {
|
||||||
|
case KERN_OPERATION_TIMED_OUT:
|
||||||
|
errno = ETIMEDOUT;
|
||||||
|
break;
|
||||||
|
case KERN_ABORTED:
|
||||||
|
errno = EINTR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ret)
|
||||||
|
errno = EINVAL;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
struct timespec wait_time;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
if (gettimeofday(&now, NULL) == -1) {
|
||||||
|
std::cerr << "Semaphore::wait(ms): Unable to get time with gettimeofday!" << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_time.tv_nsec = ((time_ms % 1000) * 1000 * 1000) + (now.tv_usec * 1000);
|
||||||
|
wait_time.tv_sec = (time_ms / 1000) + (wait_time.tv_nsec / (1000 * 1000 * 1000)) + now.tv_sec;
|
||||||
|
wait_time.tv_nsec %= 1000 * 1000 * 1000;
|
||||||
|
|
||||||
|
int ret = sem_timedwait(&semaphore, &wait_time);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
assert(!ret || (errno == ETIMEDOUT || errno == EINTR));
|
||||||
|
return !ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2013 sapier, < sapier AT gmx DOT net >
|
Copyright (C) 2013 sapier <sapier AT gmx DOT net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -17,48 +17,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef JSEMAPHORE_H_
|
#ifndef THREADING_SEMAPHORE_H
|
||||||
#define JSEMAPHORE_H_
|
#define THREADING_SEMAPHORE_H
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <assert.h>
|
|
||||||
#define MAX_SEMAPHORE_COUNT 1024
|
|
||||||
#elif defined(__MACH__) && defined(__APPLE__)
|
#elif defined(__MACH__) && defined(__APPLE__)
|
||||||
#include <pthread.h>
|
#include <mach/semaphore.h>
|
||||||
#include <mach/mach.h>
|
|
||||||
#include <mach/task.h>
|
|
||||||
#include <mach/semaphore.h>
|
|
||||||
#include <sys/semaphore.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
|
||||||
#else
|
#else
|
||||||
#include <pthread.h>
|
#include <semaphore.h>
|
||||||
#include <semaphore.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class JSemaphore {
|
|
||||||
|
class Semaphore {
|
||||||
public:
|
public:
|
||||||
JSemaphore();
|
Semaphore(int val=0);
|
||||||
~JSemaphore();
|
~Semaphore();
|
||||||
JSemaphore(int initval);
|
|
||||||
|
|
||||||
void Post();
|
void post(unsigned int num=1);
|
||||||
void Wait();
|
void wait();
|
||||||
bool Wait(unsigned int time_ms);
|
bool wait(unsigned int time_ms);
|
||||||
|
|
||||||
int GetValue();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
HANDLE m_hSemaphore;
|
HANDLE semaphore;
|
||||||
#elif defined(__MACH__) && defined(__APPLE__)
|
#elif defined(__MACH__) && defined(__APPLE__)
|
||||||
semaphore_t m_semaphore;
|
semaphore_t semaphore;
|
||||||
int semcount;
|
|
||||||
#else
|
#else
|
||||||
sem_t m_semaphore;
|
sem_t semaphore;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JSEMAPHORE_H_ */
|
|
354
src/threading/thread.cpp
Normal file
354
src/threading/thread.cpp
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "threading/thread.h"
|
||||||
|
#include "threading/mutex_auto_lock.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#include <chrono>
|
||||||
|
#else
|
||||||
|
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||||
|
# ifdef _WIN32
|
||||||
|
# ifndef _WIN32_WCE
|
||||||
|
#include <process.h>
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
#include <ctime>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
// For getNumberOfProcessors
|
||||||
|
#include <unistd.h>
|
||||||
|
# if defined(__FreeBSD__) || defined(__APPLE__)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
# elif defined(_GNU_SOURCE)
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// For setName
|
||||||
|
#if defined(linux) || defined(__linux)
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
#include <pthread_np.h>
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
struct THREADNAME_INFO {
|
||||||
|
DWORD dwType; // Must be 0x1000
|
||||||
|
LPCSTR szName; // Pointer to name (in user addr space)
|
||||||
|
DWORD dwThreadID; // Thread ID (-1=caller thread)
|
||||||
|
DWORD dwFlags; // Reserved for future use, must be zero
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For bindToProcessor
|
||||||
|
#if __FreeBSD_version >= 702106
|
||||||
|
typedef cpuset_t cpu_set_t;
|
||||||
|
#elif defined(__linux) || defined(linux)
|
||||||
|
#include <sched.h>
|
||||||
|
#elif defined(__sun) || defined(sun)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/processor.h>
|
||||||
|
#include <sys/procset.h>
|
||||||
|
#elif defined(_AIX)
|
||||||
|
#include <sys/processor.h>
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
#include <mach/thread_policy.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Thread::Thread(const std::string &name) :
|
||||||
|
name(name),
|
||||||
|
retval(NULL),
|
||||||
|
request_stop(false),
|
||||||
|
running(false)
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
, thread(NULL)
|
||||||
|
#elif !defined(_WIN32)
|
||||||
|
, started(false)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::wait()
|
||||||
|
{
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
if (!thread || !thread->joinable())
|
||||||
|
return;
|
||||||
|
thread->join();
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
if (!running)
|
||||||
|
return;
|
||||||
|
WaitForSingleObject(thread, INFINITE);
|
||||||
|
#else // pthread
|
||||||
|
void *status;
|
||||||
|
if (!started)
|
||||||
|
return;
|
||||||
|
int ret = pthread_join(thread, &status);
|
||||||
|
assert(!ret);
|
||||||
|
UNUSED(ret);
|
||||||
|
started = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Thread::start()
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
return false;
|
||||||
|
request_stop = false;
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
MutexAutoLock l(continue_mutex);
|
||||||
|
thread = new std::thread(theThread, this);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
MutexAutoLock l(continue_mutex);
|
||||||
|
# ifdef _WIN32_WCE
|
||||||
|
thread = CreateThread(NULL, 0, theThread, this, 0, &thread_id);
|
||||||
|
# else
|
||||||
|
thread = (HANDLE)_beginthreadex(NULL, 0, theThread, this, 0, &thread_id);
|
||||||
|
# endif
|
||||||
|
if (!thread)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
int status;
|
||||||
|
|
||||||
|
MutexAutoLock l(continue_mutex);
|
||||||
|
|
||||||
|
status = pthread_create(&thread, NULL, theThread, this);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
// Wait until running
|
||||||
|
while (!running) {
|
||||||
|
# ifdef _WIN32
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
struct timespec req, rem;
|
||||||
|
req.tv_sec = 0;
|
||||||
|
req.tv_nsec = 1000000;
|
||||||
|
nanosleep(&req, &rem);
|
||||||
|
}
|
||||||
|
started = true;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Thread::kill()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!running)
|
||||||
|
return false;
|
||||||
|
TerminateThread(getThreadHandle(), 0);
|
||||||
|
CloseHandle(getThreadHandle());
|
||||||
|
#else
|
||||||
|
if (!running) {
|
||||||
|
wait();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
# ifdef __ANDROID__
|
||||||
|
pthread_kill(getThreadHandle(), SIGKILL);
|
||||||
|
# else
|
||||||
|
pthread_cancel(getThreadHandle());
|
||||||
|
# endif
|
||||||
|
wait();
|
||||||
|
#endif
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
delete thread;
|
||||||
|
#endif
|
||||||
|
running = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Thread::isSameThread()
|
||||||
|
{
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
return thread->get_id() == std::this_thread::get_id();
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
return GetCurrentThreadId() == thread_id;
|
||||||
|
#else
|
||||||
|
return pthread_equal(pthread_self(), thread);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
void Thread::theThread(Thread *th)
|
||||||
|
#elif defined(_WIN32_WCE)
|
||||||
|
DWORD WINAPI Thread::theThread(void *param)
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
UINT __stdcall Thread::theThread(void *param)
|
||||||
|
#else
|
||||||
|
void *Thread::theThread(void *param)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
Thread *th = static_cast<Thread *>(param);
|
||||||
|
#endif
|
||||||
|
th->running = true;
|
||||||
|
|
||||||
|
th->setName();
|
||||||
|
log_register_thread(th->name);
|
||||||
|
|
||||||
|
th->retval = th->run();
|
||||||
|
|
||||||
|
log_deregister_thread();
|
||||||
|
|
||||||
|
th->running = false;
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
# ifdef _WIN32
|
||||||
|
CloseHandle(th->thread);
|
||||||
|
# endif
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::setName(const std::string &name)
|
||||||
|
{
|
||||||
|
#if defined(linux) || defined(__linux)
|
||||||
|
/* It would be cleaner to do this with pthread_setname_np,
|
||||||
|
* which was added to glibc in version 2.12, but some major
|
||||||
|
* distributions are still runing 2.11 and previous versions.
|
||||||
|
*/
|
||||||
|
prctl(PR_SET_NAME, name.c_str());
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
pthread_set_name_np(pthread_self(), name.c_str());
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
pthread_setname_np(pthread_self(), name.c_str());
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
pthread_setname_np(name.c_str());
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
// Windows itself doesn't support thread names,
|
||||||
|
// but the MSVC debugger does...
|
||||||
|
THREADNAME_INFO info;
|
||||||
|
info.dwType = 0x1000;
|
||||||
|
info.szName = name.c_str();
|
||||||
|
info.dwThreadID = -1;
|
||||||
|
info.dwFlags = 0;
|
||||||
|
__try {
|
||||||
|
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
|
||||||
|
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
||||||
|
}
|
||||||
|
#elif defined(_WIN32) || defined(__GNU__)
|
||||||
|
// These platforms are known to not support thread names.
|
||||||
|
// Silently ignore the request.
|
||||||
|
#else
|
||||||
|
#warning "Unrecognized platform, thread names will not be available."
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int Thread::getNumberOfProcessors()
|
||||||
|
{
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
return std::thread::hardware_concurrency();
|
||||||
|
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
#elif defined(__FreeBSD__) || defined(__APPLE__)
|
||||||
|
unsigned int len, count;
|
||||||
|
len = sizeof(count);
|
||||||
|
return sysctlbyname("hw.ncpu", &count, &len, NULL, 0);
|
||||||
|
#elif defined(_GNU_SOURCE)
|
||||||
|
return get_nprocs();
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
SYSTEM_INFO sysinfo;
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
return sysinfo.dwNumberOfProcessors;
|
||||||
|
#elif defined(PTW32_VERSION) || defined(__hpux)
|
||||||
|
return pthread_num_processors_np();
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Thread::bindToProcessor(unsigned int num)
|
||||||
|
{
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
return false;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
return SetThreadAffinityMask(getThreadHandle(), 1 << num);
|
||||||
|
#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
|
||||||
|
cpu_set_t cpuset;
|
||||||
|
CPU_ZERO(&cpuset);
|
||||||
|
CPU_SET(num, &cpuset);
|
||||||
|
return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset),
|
||||||
|
&cpuset) == 0;
|
||||||
|
#elif defined(__sun) || defined(sun)
|
||||||
|
return processor_bind(P_LWPID, MAKE_LWPID_PTHREAD(getThreadHandle()),
|
||||||
|
num, NULL) == 0
|
||||||
|
#elif defined(_AIX)
|
||||||
|
return bindprocessor(BINDTHREAD, (tid_t) getThreadHandle(), pnumber) == 0;
|
||||||
|
#elif defined(__hpux) || defined(hpux)
|
||||||
|
pthread_spu_t answer;
|
||||||
|
|
||||||
|
return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
|
||||||
|
&answer, num, getThreadHandle()) == 0;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
struct thread_affinity_policy tapol;
|
||||||
|
|
||||||
|
thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
|
||||||
|
tapol.affinity_tag = num + 1;
|
||||||
|
return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
|
||||||
|
(thread_policy_t)&tapol,
|
||||||
|
THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Thread::setPriority(int prio)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return SetThreadPriority(getThreadHandle(), prio);
|
||||||
|
#else
|
||||||
|
struct sched_param sparam;
|
||||||
|
int policy;
|
||||||
|
|
||||||
|
if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int min = sched_get_priority_min(policy);
|
||||||
|
int max = sched_get_priority_max(policy);
|
||||||
|
|
||||||
|
sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
|
||||||
|
return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
119
src/threading/thread.h
Normal file
119
src/threading/thread.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the JThread package, which contains some object-
|
||||||
|
oriented thread wrappers for different thread implementations.
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREADING_THREAD_H
|
||||||
|
#define THREADING_THREAD_H
|
||||||
|
|
||||||
|
#include "threading/atomic.h"
|
||||||
|
#include "threading/mutex.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#include <thread>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
enum {
|
||||||
|
THREAD_PRIORITY_LOWEST,
|
||||||
|
THREAD_PRIORITY_BELOW_NORMAL,
|
||||||
|
THREAD_PRIORITY_NORMAL,
|
||||||
|
THREAD_PRIORITY_ABOVE_NORMAL,
|
||||||
|
THREAD_PRIORITY_HIGHEST,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Thread(const std::string &name="Unnamed");
|
||||||
|
virtual ~Thread() { kill(); }
|
||||||
|
|
||||||
|
bool start();
|
||||||
|
inline void stop() { request_stop = true; }
|
||||||
|
bool kill();
|
||||||
|
|
||||||
|
inline bool isRunning() { return running; }
|
||||||
|
inline bool stopRequested() { return request_stop; }
|
||||||
|
void *getReturnValue() { return running ? NULL : retval; }
|
||||||
|
bool isSameThread();
|
||||||
|
|
||||||
|
static unsigned int getNumberOfProcessors();
|
||||||
|
bool bindToProcessor(unsigned int);
|
||||||
|
bool setPriority(int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for thread to finish.
|
||||||
|
* Note: this does not stop a thread, you have to do this on your own.
|
||||||
|
* Returns immediately if the thread is not started.
|
||||||
|
*/
|
||||||
|
void wait();
|
||||||
|
|
||||||
|
static void setName(const std::string &name);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
virtual void *run() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setName() { setName(name); }
|
||||||
|
|
||||||
|
void *retval;
|
||||||
|
Atomic<bool> request_stop;
|
||||||
|
Atomic<bool> running;
|
||||||
|
Mutex continue_mutex;
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
static void theThread(Thread *th);
|
||||||
|
|
||||||
|
std::thread *thread;
|
||||||
|
std::thread::native_handle_type getThreadHandle() const
|
||||||
|
{ return thread->native_handle(); }
|
||||||
|
#else
|
||||||
|
# if defined(WIN32) || defined(_WIN32_WCE)
|
||||||
|
# ifdef _WIN32_WCE
|
||||||
|
DWORD thread_id;
|
||||||
|
static DWORD WINAPI theThread(void *param);
|
||||||
|
# else
|
||||||
|
UINT thread_id;
|
||||||
|
static UINT __stdcall theThread(void *param);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
HANDLE thread;
|
||||||
|
HANDLE getThreadHandle() const { return thread; }
|
||||||
|
# else // pthread
|
||||||
|
static void *theThread(void *param);
|
||||||
|
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_t getThreadHandle() const { return thread; }
|
||||||
|
|
||||||
|
Atomic<bool> started;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -20,9 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#ifndef THREADS_HEADER
|
#ifndef THREADS_HEADER
|
||||||
#define THREADS_HEADER
|
#define THREADS_HEADER
|
||||||
|
|
||||||
#include "jthread/jmutex.h"
|
#include "threading/mutex.h"
|
||||||
|
|
||||||
#if (defined(WIN32) || defined(_WIN32_WCE))
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
||||||
typedef DWORD threadid_t;
|
typedef DWORD threadid_t;
|
||||||
#else
|
#else
|
||||||
typedef pthread_t threadid_t;
|
typedef pthread_t threadid_t;
|
||||||
@ -30,7 +30,7 @@ typedef pthread_t threadid_t;
|
|||||||
|
|
||||||
inline threadid_t get_current_thread_id()
|
inline threadid_t get_current_thread_id()
|
||||||
{
|
{
|
||||||
#if (defined(WIN32) || defined(_WIN32_WCE))
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
||||||
return GetCurrentThreadId();
|
return GetCurrentThreadId();
|
||||||
#else
|
#else
|
||||||
return pthread_self();
|
return pthread_self();
|
||||||
|
@ -17,6 +17,7 @@ set (UNITTEST_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_serialization.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_serialization.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_settings.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_settings.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_socket.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_socket.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test_threading.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_utilities.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_utilities.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_voxelalgorithms.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_voxelalgorithms.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_voxelmanipulator.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_voxelmanipulator.cpp
|
||||||
|
85
src/unittest/test_threading.cpp
Normal file
85
src/unittest/test_threading.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "threading/atomic.h"
|
||||||
|
#include "threading/semaphore.h"
|
||||||
|
#include "threading/thread.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TestThreading : public TestBase {
|
||||||
|
public:
|
||||||
|
TestThreading() { TestManager::registerTestModule(this); }
|
||||||
|
const char *getName() { return "TestThreading"; }
|
||||||
|
void runTests(IGameDef *);
|
||||||
|
void testAtomicSemaphoreThread();
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestThreading g_test_instance;
|
||||||
|
|
||||||
|
void TestThreading::runTests(IGameDef *)
|
||||||
|
{
|
||||||
|
TEST(testAtomicSemaphoreThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AtomicTestThread : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AtomicTestThread(Atomic<u32> &v, Semaphore &trigger) :
|
||||||
|
Thread("AtomicTest"),
|
||||||
|
val(v),
|
||||||
|
trigger(trigger)
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
void *run()
|
||||||
|
{
|
||||||
|
trigger.wait();
|
||||||
|
for (u32 i = 0; i < 0x10000; ++i)
|
||||||
|
++val;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Atomic<u32> &val;
|
||||||
|
Semaphore &trigger;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void TestThreading::testAtomicSemaphoreThread()
|
||||||
|
{
|
||||||
|
Atomic<u32> val;
|
||||||
|
Semaphore trigger;
|
||||||
|
static const u8 num_threads = 4;
|
||||||
|
|
||||||
|
AtomicTestThread *threads[num_threads];
|
||||||
|
for (u8 i = 0; i < num_threads; ++i) {
|
||||||
|
threads[i] = new AtomicTestThread(val, trigger);
|
||||||
|
UASSERT(threads[i]->start());
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.post(num_threads);
|
||||||
|
|
||||||
|
for (u8 i = 0; i < num_threads; ++i) {
|
||||||
|
threads[i]->wait();
|
||||||
|
delete threads[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
UASSERT(val == num_threads * 0x10000);
|
||||||
|
}
|
||||||
|
|
@ -22,9 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "../irrlichttypes.h"
|
#include "../irrlichttypes.h"
|
||||||
#include "../exceptions.h"
|
#include "../exceptions.h"
|
||||||
#include "../jthread/jmutex.h"
|
#include "../threading/mutex.h"
|
||||||
#include "../jthread/jmutexautolock.h"
|
#include "../threading/mutex_auto_lock.h"
|
||||||
#include "../jthread/jsemaphore.h"
|
#include "../threading/semaphore.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -81,111 +81,47 @@ template<typename Key, typename Value>
|
|||||||
class MutexedMap
|
class MutexedMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MutexedMap()
|
MutexedMap() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(const Key &name, const Value &value)
|
void set(const Key &name, const Value &value)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
m_values[name] = value;
|
m_values[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get(const Key &name, Value *result)
|
bool get(const Key &name, Value *result) const
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
typename std::map<Key, Value>::const_iterator n =
|
||||||
typename std::map<Key, Value>::iterator n;
|
m_values.find(name);
|
||||||
n = m_values.find(name);
|
if (n == m_values.end())
|
||||||
|
|
||||||
if(n == m_values.end())
|
|
||||||
return false;
|
return false;
|
||||||
|
if (result)
|
||||||
if(result != NULL)
|
|
||||||
*result = n->second;
|
*result = n->second;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> getValues()
|
std::vector<Value> getValues() const
|
||||||
{
|
{
|
||||||
|
MutexAutoLock lock(m_mutex);
|
||||||
std::vector<Value> result;
|
std::vector<Value> result;
|
||||||
for(typename std::map<Key, Value>::iterator
|
for (typename std::map<Key, Value>::const_iterator
|
||||||
i = m_values.begin();
|
it = m_values.begin();
|
||||||
i != m_values.end(); ++i){
|
it != m_values.end(); ++it){
|
||||||
result.push_back(i->second);
|
result.push_back(it->second);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear ()
|
void clear() { m_values.clear(); }
|
||||||
{
|
|
||||||
m_values.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<Key, Value> m_values;
|
std::map<Key, Value> m_values;
|
||||||
JMutex m_mutex;
|
mutable Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
Generates ids for comparable values.
|
|
||||||
Id=0 is reserved for "no value".
|
|
||||||
|
|
||||||
Is fast at:
|
// Thread-safe Double-ended queue
|
||||||
- Returning value by id (very fast)
|
|
||||||
- Returning id by value
|
|
||||||
- Generating a new id for a value
|
|
||||||
|
|
||||||
Is not able to:
|
|
||||||
- Remove an id/value pair (is possible to implement but slow)
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
class MutexedIdGenerator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MutexedIdGenerator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if found
|
|
||||||
bool getValue(u32 id, T &value)
|
|
||||||
{
|
|
||||||
if(id == 0)
|
|
||||||
return false;
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
|
||||||
if(m_id_to_value.size() < id)
|
|
||||||
return false;
|
|
||||||
value = m_id_to_value[id-1];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If id exists for value, returns the id.
|
|
||||||
// Otherwise generates an id for the value.
|
|
||||||
u32 getId(const T &value)
|
|
||||||
{
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
|
||||||
typename std::map<T, u32>::iterator n;
|
|
||||||
n = m_value_to_id.find(value);
|
|
||||||
if(n != m_value_to_id.end())
|
|
||||||
return n->second;
|
|
||||||
m_id_to_value.push_back(value);
|
|
||||||
u32 new_id = m_id_to_value.size();
|
|
||||||
m_value_to_id.insert(value, new_id);
|
|
||||||
return new_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JMutex m_mutex;
|
|
||||||
// Values are stored here at id-1 position (id 1 = [0])
|
|
||||||
std::vector<T> m_id_to_value;
|
|
||||||
std::map<T, u32> m_value_to_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Thread-safe FIFO queue (well, actually a FILO also)
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class MutexedQueue
|
class MutexedQueue
|
||||||
@ -194,19 +130,18 @@ public:
|
|||||||
template<typename Key, typename U, typename Caller, typename CallerData>
|
template<typename Key, typename U, typename Caller, typename CallerData>
|
||||||
friend class RequestQueue;
|
friend class RequestQueue;
|
||||||
|
|
||||||
MutexedQueue()
|
MutexedQueue() {}
|
||||||
|
bool empty() const
|
||||||
{
|
{
|
||||||
|
MutexAutoLock lock(m_mutex);
|
||||||
|
return m_queue.empty();
|
||||||
}
|
}
|
||||||
bool empty()
|
|
||||||
{
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
|
||||||
return (m_queue.size() == 0);
|
|
||||||
}
|
|
||||||
void push_back(T t)
|
void push_back(T t)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
m_queue.push_back(t);
|
m_queue.push_back(t);
|
||||||
m_size.Post();
|
m_signal.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this version of pop_front returns a empty element of T on timeout.
|
/* this version of pop_front returns a empty element of T on timeout.
|
||||||
@ -214,37 +149,35 @@ public:
|
|||||||
*/
|
*/
|
||||||
T pop_frontNoEx(u32 wait_time_max_ms)
|
T pop_frontNoEx(u32 wait_time_max_ms)
|
||||||
{
|
{
|
||||||
if (m_size.Wait(wait_time_max_ms)) {
|
if (m_signal.wait(wait_time_max_ms)) {
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.front();
|
T t = m_queue.front();
|
||||||
m_queue.pop_front();
|
m_queue.pop_front();
|
||||||
return t;
|
return t;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T pop_front(u32 wait_time_max_ms)
|
T pop_front(u32 wait_time_max_ms)
|
||||||
{
|
{
|
||||||
if (m_size.Wait(wait_time_max_ms)) {
|
if (m_signal.wait(wait_time_max_ms)) {
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.front();
|
T t = m_queue.front();
|
||||||
m_queue.pop_front();
|
m_queue.pop_front();
|
||||||
return t;
|
return t;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw ItemNotFoundException("MutexedQueue: queue is empty");
|
throw ItemNotFoundException("MutexedQueue: queue is empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T pop_frontNoEx()
|
T pop_frontNoEx()
|
||||||
{
|
{
|
||||||
m_size.Wait();
|
m_signal.wait();
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.front();
|
T t = m_queue.front();
|
||||||
m_queue.pop_front();
|
m_queue.pop_front();
|
||||||
@ -253,14 +186,13 @@ public:
|
|||||||
|
|
||||||
T pop_back(u32 wait_time_max_ms=0)
|
T pop_back(u32 wait_time_max_ms=0)
|
||||||
{
|
{
|
||||||
if (m_size.Wait(wait_time_max_ms)) {
|
if (m_signal.wait(wait_time_max_ms)) {
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.back();
|
T t = m_queue.back();
|
||||||
m_queue.pop_back();
|
m_queue.pop_back();
|
||||||
return t;
|
return t;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw ItemNotFoundException("MutexedQueue: queue is empty");
|
throw ItemNotFoundException("MutexedQueue: queue is empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,25 +200,24 @@ public:
|
|||||||
/* this version of pop_back returns a empty element of T on timeout.
|
/* this version of pop_back returns a empty element of T on timeout.
|
||||||
* Make sure default constructor of T creates a recognizable "empty" element
|
* Make sure default constructor of T creates a recognizable "empty" element
|
||||||
*/
|
*/
|
||||||
T pop_backNoEx(u32 wait_time_max_ms=0)
|
T pop_backNoEx(u32 wait_time_max_ms)
|
||||||
{
|
{
|
||||||
if (m_size.Wait(wait_time_max_ms)) {
|
if (m_signal.wait(wait_time_max_ms)) {
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.back();
|
T t = m_queue.back();
|
||||||
m_queue.pop_back();
|
m_queue.pop_back();
|
||||||
return t;
|
return t;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T pop_backNoEx()
|
T pop_backNoEx()
|
||||||
{
|
{
|
||||||
m_size.Wait();
|
m_signal.wait();
|
||||||
|
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
T t = m_queue.back();
|
T t = m_queue.back();
|
||||||
m_queue.pop_back();
|
m_queue.pop_back();
|
||||||
@ -294,19 +225,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JMutex & getMutex()
|
Mutex &getMutex() { return m_mutex; }
|
||||||
{
|
|
||||||
return m_mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<T> & getQueue()
|
std::deque<T> &getQueue() { return m_queue; }
|
||||||
{
|
|
||||||
return m_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<T> m_queue;
|
std::deque<T> m_queue;
|
||||||
JMutex m_mutex;
|
mutable Mutex m_mutex;
|
||||||
JSemaphore m_size;
|
Semaphore m_signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename K, typename V>
|
template<typename K, typename V>
|
||||||
|
@ -23,17 +23,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "../constants.h" // BS, MAP_BLOCKSIZE
|
#include "../constants.h" // BS, MAP_BLOCKSIZE
|
||||||
#include "../noise.h" // PseudoRandom, PcgRandom
|
#include "../noise.h" // PseudoRandom, PcgRandom
|
||||||
#include "../jthread/jmutexautolock.h"
|
#include "../threading/mutex_auto_lock.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
std::map<u16, std::vector<v3s16> > FacePositionCache::m_cache;
|
std::map<u16, std::vector<v3s16> > FacePositionCache::m_cache;
|
||||||
JMutex FacePositionCache::m_cache_mutex;
|
Mutex FacePositionCache::m_cache_mutex;
|
||||||
// Calculate the borders of a "d-radius" cube
|
// Calculate the borders of a "d-radius" cube
|
||||||
// TODO: Make it work without mutex and data races, probably thread-local
|
// TODO: Make it work without mutex and data races, probably thread-local
|
||||||
std::vector<v3s16> FacePositionCache::getFacePositions(u16 d)
|
std::vector<v3s16> FacePositionCache::getFacePositions(u16 d)
|
||||||
{
|
{
|
||||||
JMutexAutoLock cachelock(m_cache_mutex);
|
MutexAutoLock cachelock(m_cache_mutex);
|
||||||
if (m_cache.find(d) != m_cache.end())
|
if (m_cache.find(d) != m_cache.end())
|
||||||
return m_cache[d];
|
return m_cache[d];
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "../irr_v2d.h"
|
#include "../irr_v2d.h"
|
||||||
#include "../irr_v3d.h"
|
#include "../irr_v3d.h"
|
||||||
#include "../irr_aabb3d.h"
|
#include "../irr_aabb3d.h"
|
||||||
#include "../jthread/jmutex.h"
|
#include "../threading/mutex.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -42,7 +42,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
static void generateFacePosition(u16 d);
|
static void generateFacePosition(u16 d);
|
||||||
static std::map<u16, std::vector<v3s16> > m_cache;
|
static std::map<u16, std::vector<v3s16> > m_cache;
|
||||||
static JMutex m_cache_mutex;
|
static Mutex m_cache_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndentationRaiser
|
class IndentationRaiser
|
||||||
|
@ -21,9 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#define UTIL_THREAD_HEADER
|
#define UTIL_THREAD_HEADER
|
||||||
|
|
||||||
#include "../irrlichttypes.h"
|
#include "../irrlichttypes.h"
|
||||||
#include "../jthread/jthread.h"
|
#include "../threading/thread.h"
|
||||||
#include "../jthread/jmutex.h"
|
#include "../threading/mutex.h"
|
||||||
#include "../jthread/jmutexautolock.h"
|
#include "../threading/mutex_auto_lock.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
@ -36,27 +36,27 @@ public:
|
|||||||
|
|
||||||
T get()
|
T get()
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(T value)
|
void set(T value)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
m_value = value;
|
m_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You'll want to grab this in a SharedPtr
|
// You'll want to grab this in a SharedPtr
|
||||||
JMutexAutoLock *getLock()
|
MutexAutoLock *getLock()
|
||||||
{
|
{
|
||||||
return new JMutexAutoLock(m_mutex);
|
return new MutexAutoLock(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// You pretty surely want to grab the lock when accessing this
|
// You pretty surely want to grab the lock when accessing this
|
||||||
T m_value;
|
T m_value;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JMutex m_mutex;
|
Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -118,7 +118,7 @@ public:
|
|||||||
typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator j;
|
typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator j;
|
||||||
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_queue.getMutex());
|
MutexAutoLock lock(m_queue.getMutex());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the caller is already on the list, only update CallerData
|
If the caller is already on the list, only update CallerData
|
||||||
@ -192,44 +192,33 @@ private:
|
|||||||
MutexedQueue<GetRequest<Key, T, Caller, CallerData> > m_queue;
|
MutexedQueue<GetRequest<Key, T, Caller, CallerData> > m_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UpdateThread : public JThread {
|
class UpdateThread : public Thread
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
UpdateThread() {}
|
UpdateThread(const std::string &name) : Thread(name + "Update") {}
|
||||||
virtual ~UpdateThread() {}
|
~UpdateThread() {}
|
||||||
|
|
||||||
void deferUpdate()
|
void deferUpdate() { m_update_sem.post(); }
|
||||||
{
|
|
||||||
m_update_sem.Post();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stop()
|
void stop()
|
||||||
{
|
{
|
||||||
JThread::Stop();
|
Thread::stop();
|
||||||
|
|
||||||
// give us a nudge
|
// give us a nudge
|
||||||
m_update_sem.Post();
|
m_update_sem.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Thread()
|
void *run()
|
||||||
{
|
{
|
||||||
ThreadStarted();
|
|
||||||
|
|
||||||
const char *thread_name = getName();
|
|
||||||
log_register_thread(thread_name);
|
|
||||||
porting::setThreadName(thread_name);
|
|
||||||
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
|
|
||||||
while (!StopRequested()) {
|
while (!stopRequested()) {
|
||||||
m_update_sem.Wait();
|
m_update_sem.wait();
|
||||||
|
// Set semaphore to 0
|
||||||
|
while (m_update_sem.wait(0));
|
||||||
|
|
||||||
// Empty the queue, just in case doUpdate() is expensive
|
if (stopRequested()) break;
|
||||||
while (m_update_sem.GetValue())
|
|
||||||
m_update_sem.Wait();
|
|
||||||
|
|
||||||
if (StopRequested())
|
|
||||||
break;
|
|
||||||
|
|
||||||
doUpdate();
|
doUpdate();
|
||||||
}
|
}
|
||||||
@ -241,10 +230,9 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void doUpdate() = 0;
|
virtual void doUpdate() = 0;
|
||||||
virtual const char *getName() = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSemaphore m_update_sem;
|
Semaphore m_update_sem;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user