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:
ShadowNinja 2015-04-07 06:13:12 -04:00
parent 6a1047d8c1
commit e4bff8be94
77 changed files with 1594 additions and 2046 deletions

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)

@ -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();

@ -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();
}

@ -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;
} }
@ -1257,6 +1257,7 @@ SharedBuffer<u8> UDPPeer::addSpiltPacket(u8 channel,
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,14 +969,14 @@ 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;
} }
@ -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;
}; };

@ -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;

@ -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(); \

@ -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();

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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/mach.h>
#include <mach/task.h>
#include <mach/semaphore.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

@ -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

@ -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

@ -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