diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-02-15 16:11:24 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-02-15 16:11:24 +0200 |
commit | d065bae323838734556de2693b6b004c98c95092 (patch) | |
tree | c51888cc0c2628f1a3e5cd2ba05b4297c2a22869 | |
parent | be7391c2b1153c817a69aabd2a34e082c79df58f (diff) | |
download | minetest-d065bae323838734556de2693b6b004c98c95092.tar.gz minetest-d065bae323838734556de2693b6b004c98c95092.tar.bz2 minetest-d065bae323838734556de2693b6b004c98c95092.zip |
Ctrl+C handling on POSIX, some commands for server and other tweaking
-rw-r--r-- | doc/changelog.txt | 2 | ||||
-rw-r--r-- | minetest.conf.example | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/guiPauseMenu.cpp | 14 | ||||
-rw-r--r-- | src/main.cpp | 33 | ||||
-rw-r--r-- | src/mapblock.cpp | 12 | ||||
-rw-r--r-- | src/porting.cpp | 47 | ||||
-rw-r--r-- | src/porting.h | 11 | ||||
-rw-r--r-- | src/server.cpp | 282 | ||||
-rw-r--r-- | src/server.h | 32 | ||||
-rw-r--r-- | src/servermain.cpp | 18 | ||||
-rw-r--r-- | src/test.cpp | 2 | ||||
-rw-r--r-- | src/utility.h | 34 |
13 files changed, 384 insertions, 111 deletions
diff --git a/doc/changelog.txt b/doc/changelog.txt index 424f98bcf..a8722f1c9 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,5 +1,7 @@ Minetest-c55 changelog ---------------------- +This should contain all the major changes. +For minor stuff, refer to the commit log of the repository. 2011-02-14: - Created changelog.txt diff --git a/minetest.conf.example b/minetest.conf.example index 264d77e5a..37c93a5a2 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -31,6 +31,8 @@ #map-dir = /home/palle/custom_map +#operator_name = + #plants_amount = 1.0 #ravines_amount = 1.0 #coal_amount = 1.0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7fefc0238..6d9601c65 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ if(RUN_IN_PLACE) add_definitions ( -DRUN_IN_PLACE ) endif(RUN_IN_PLACE) +set(USE_GPROF 0 CACHE BOOL "Use -pg flag for g++") + # Use cmake_config.h add_definitions ( -DUSE_CMAKE_CONFIG_H ) @@ -161,6 +163,10 @@ else() set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops") set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall") + + if(USE_GPROF) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg") + endif() if(BUILD_SERVER) set_target_properties(minetestserver PROPERTIES diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp index b6f913d6b..2d42fdb77 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -174,10 +174,18 @@ bool GUIPauseMenu::OnEvent(const SEvent& event) {
if(event.EventType==EET_KEY_INPUT_EVENT)
{
- if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
+ if(event.KeyInput.PressedDown)
{
- quitMenu();
- return true;
+ if(event.KeyInput.Key==KEY_ESCAPE)
+ {
+ quitMenu();
+ return true;
+ }
+ else if(event.KeyInput.Key==KEY_RETURN)
+ {
+ quitMenu();
+ return true;
+ }
}
}
if(event.EventType==EET_GUI_EVENT)
diff --git a/src/main.cpp b/src/main.cpp index bcc8dc446..452030a24 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -268,7 +268,7 @@ Doing now (most important at the top): # maybe done
* not done
-=== Stuff to do before release
+=== Fixmes
* Make server find the spawning place from the real map data, not from
the heightmap
- But the changing borders of chunk have to be avoided, because
@@ -277,15 +277,15 @@ Doing now (most important at the top): placement and transfer
* only_from_disk might not work anymore - check and fix it.
* Check the fixmes in the list above
-* FIXME: Sneaking doesn't switch sneak node when moving sideways
+* When sending blocks to the client, the server takes way too much
+ CPU time (20-30% for single player), find out what it is doing.
+ - Make a simple profiler
=== Making it more portable
* Some MSVC: std::sto* are defined without a namespace and collide
with the ones in utility.h
-* On Kray's machine, the new find_library(XXF86VM_LIBRARY, Xxf86vm)
- line doesn't find the library.
-=== Stuff to do after release
+=== Features
* Make an "environment metafile" to store at least time of day
* Move digging property stuff from material.{h,cpp} to mapnode.cpp...
- Or maybe move content_features to material.{h,cpp}?
@@ -567,7 +567,25 @@ struct TextDestChat : public TextDest }
void gotText(std::wstring text)
{
+ // Discard empty line
+ if(text == L"")
+ return;
+
+ // Parse command (server command starts with "/#")
+ if(text[0] == L'/' && text[1] != L'#')
+ {
+ std::wstring reply = L"Local: ";
+
+ reply += L"Local commands not yet supported. "
+ "Server prefix is \"/#\".";
+
+ m_client->addChatMessage(reply);
+ return;
+ }
+
+ // Send to others
m_client->sendChatMessage(text);
+ // Show locally
m_client->addChatMessage(text);
}
@@ -1546,6 +1564,9 @@ int main(int argc, char *argv[]) DSTACK(__FUNCTION_NAME);
+ porting::signal_handler_init();
+ bool &kill = *porting::signal_handler_killstatus();
+
porting::initializePaths();
// Create user data directory
fs::CreateDir(porting::path_userdata);
@@ -1681,7 +1702,7 @@ int main(int argc, char *argv[]) server.start(port);
// Run server
- dedicated_server_loop(server);
+ dedicated_server_loop(server, kill);
return 0;
}
diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 422d3b531..1dbbe5c4e 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -1771,11 +1771,11 @@ void MapBlock::serialize(std::ostream &os, u8 version) // First byte u8 flags = 0; if(is_underground) - flags |= 1; + flags |= 0x01; if(m_day_night_differs) - flags |= 2; + flags |= 0x02; if(m_lighting_expired) - flags |= 3; + flags |= 0x04; os.write((char*)&flags, 1); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; @@ -1895,9 +1895,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version) u8 flags; is.read((char*)&flags, 1); - is_underground = (flags & 1) ? true : false; - m_day_night_differs = (flags & 2) ? true : false; - m_lighting_expired = (flags & 3) ? true : false; + is_underground = (flags & 0x01) ? true : false; + m_day_night_differs = (flags & 0x02) ? true : false; + m_lighting_expired = (flags & 0x04) ? true : false; // Uncompress data std::ostringstream os(std::ios_base::binary); diff --git a/src/porting.cpp b/src/porting.cpp index 592636336..f92b291ac 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -29,6 +29,53 @@ with this program; if not, write to the Free Software Foundation, Inc., namespace porting { +/* + Signal handler (grabs Ctrl-C on POSIX systems) +*/ + +#if !defined(_WIN32) // POSIX + #include <signal.h> + +bool g_killed = false; + +void sigint_handler(int sig) +{ + if(g_killed == false) + { + dstream<<DTIME<<"sigint_handler(): " + <<"Ctrl-C pressed, shutting down."<<std::endl; + g_killed = true; + } + else + { + (void)signal(SIGINT, SIG_DFL); + } +} + +void signal_handler_init(void) +{ + dstream<<"signal_handler_init()"<<std::endl; + (void)signal(SIGINT, sigint_handler); +} + +#else // _WIN32 + +void signal_handler_init(void) +{ + // No-op +} + +#endif + +bool * signal_handler_killstatus(void) +{ + return &g_killed; +} + +/* + Path mangler +*/ + std::string path_data = "../data"; std::string path_userdata = "../"; diff --git a/src/porting.h b/src/porting.h index 3133fcc80..3cf8df594 100644 --- a/src/porting.h +++ b/src/porting.h @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PORTING_HEADER #include <string> -// Included for u64 and such +// Included for u32 and such #include "common_irrlicht.h" #include "debug.h" #include "constants.h" @@ -48,6 +48,15 @@ namespace porting { /* + Signal handler (grabs Ctrl-C on POSIX systems) +*/ + +void signal_handler_init(void); +// Returns a pointer to a bool. +// When the bool is true, program should quit. +bool * signal_handler_killstatus(void); + +/* Path of static data directory. */ extern std::string path_data; diff --git a/src/server.cpp b/src/server.cpp index dc72661ff..31ebfacbb 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -46,7 +46,12 @@ void * ServerThread::Thread() while(getRun()) { try{ - m_server->AsyncRunStep(); + //TimeTaker timer("AsyncRunStep() + Receive()"); + + { + //TimeTaker timer("AsyncRunStep()"); + m_server->AsyncRunStep(); + } //dout_server<<"Running m_server->Receive()"<<std::endl; m_server->Receive(); @@ -967,7 +972,8 @@ Server::Server( m_time_counter(0), m_time_of_day_send_timer(0), m_uptime(0), - m_mapsavedir(mapsavedir) + m_mapsavedir(mapsavedir), + m_shutdown_requested(false) { //m_flowwater_timer = 0.0; m_liquid_transform_timer = 0.0; @@ -987,28 +993,62 @@ Server::Server( Server::~Server() { - // Save players + /* + Send shutdown message + */ + { + JMutexAutoLock conlock(m_con_mutex); + + std::wstring line = L"*** Server shutting down"; + + /* + Send the message to clients + */ + for(core::map<u16, RemoteClient*>::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + // Get client and check that it is valid + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + SendChatMessage(client->peer_id, line); + } + } + + /* + Save players + */ m_env.serializePlayers(m_mapsavedir); - // Stop threads + /* + Stop threads + */ stop(); - - JMutexAutoLock clientslock(m_con_mutex); - - for(core::map<u16, RemoteClient*>::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) + + /* + Delete clients + */ { - /*// Delete player - // NOTE: These are removed by env destructor + JMutexAutoLock clientslock(m_con_mutex); + + for(core::map<u16, RemoteClient*>::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) { - u16 peer_id = i.getNode()->getKey(); - JMutexAutoLock envlock(m_env_mutex); - m_env.removePlayer(peer_id); - }*/ - - // Delete client - delete i.getNode()->getValue(); + /*// Delete player + // NOTE: These are removed by env destructor + { + u16 peer_id = i.getNode()->getKey(); + JMutexAutoLock envlock(m_env_mutex); + m_env.removePlayer(peer_id); + }*/ + + // Delete client + delete i.getNode()->getValue(); + } } } @@ -1586,39 +1626,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) m_time_of_day.get()); m_con.Send(peer->id, 0, data, true); } - + // Send information about server to player in chat - { - std::wostringstream os(std::ios_base::binary); - os<<L"# Server: "; - // Uptime - os<<L"uptime="<<m_uptime.get(); - // Information about clients - os<<L", clients={"; - for(core::map<u16, RemoteClient*>::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - // Get client and check that it is valid - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - // Get player - Player *player = m_env.getPlayer(client->peer_id); - // Get name of player - std::wstring name = L"unknown"; - if(player != NULL) - name = narrow_to_wide(player->getName()); - // Add name to information string - os<<name<<L","; - } - os<<L"}"; - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false) - os<<" WARNING: Map saving is disabled."<<std::endl; - // Send message - SendChatMessage(peer_id, os.str()); - } + SendChatMessage(peer_id, getStatusString()); // Send information about joining in chat { @@ -2461,29 +2471,115 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Get player name of this client std::wstring name = narrow_to_wide(player->getName()); - - std::wstring line = std::wstring(L"<")+name+L"> "+message; - dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl; - - /* - Send the message to all other clients - */ - for(core::map<u16, RemoteClient*>::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) + // Line to send to players + std::wstring line; + // Whether to send to the player that sent the line + bool send_to_sender = false; + // Whether to send to other players + bool send_to_others = false; + + // Parse commands + std::wstring commandprefix = L"/#"; + if(message.substr(0, commandprefix.size()) == commandprefix) + { + line += L"Server: "; + + message = message.substr(commandprefix.size()); + // Get player name as narrow string + std::string name_s = player->getName(); + // Convert message to narrow string + std::string message_s = wide_to_narrow(message); + // Operator is the single name defined in config. + std::string operator_name = g_settings.get("name"); + bool is_operator = (operator_name != "" && + wide_to_narrow(name) == operator_name); + bool valid_command = false; + if(message_s == "help") + { + line += L"-!- Available commands: "; + line += L"status "; + if(is_operator) + { + line += L"shutdown setting "; + } + else + { + } + send_to_sender = true; + valid_command = true; + } + else if(message_s == "status") + { + line = getStatusString(); + send_to_sender = true; + valid_command = true; + } + else if(is_operator) + { + if(message_s == "shutdown") + { + dstream<<DTIME<<" Server: Operator requested shutdown." + <<std::endl; + m_shutdown_requested.set(true); + + line += L"*** Server shutting down (operator request)"; + send_to_sender = true; + valid_command = true; + } + else if(message_s.substr(0,8) == "setting ") + { + std::string confline = message_s.substr(8); + g_settings.parseConfigLine(confline); + line += L"-!- Setting changed."; + send_to_sender = true; + valid_command = true; + } + } + + if(valid_command == false) + { + line += L"-!- Invalid command: " + message; + send_to_sender = true; + } + } + else { - // Get client and check that it is valid - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; + line += L"<"; + /*if(is_operator) + line += L"@";*/ + line += name; + line += L"> "; + line += message; + send_to_others = true; + } + + if(line != L"") + { + dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl; - // Don't send if it's the same one - if(peer_id == client->peer_id) - continue; + /* + Send the message to clients + */ + for(core::map<u16, RemoteClient*>::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + // Get client and check that it is valid + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; - SendChatMessage(client->peer_id, line); + // Filter recipient + bool sender_selected = (peer_id == client->peer_id); + if(sender_selected == true && send_to_sender == false) + continue; + if(sender_selected == false && send_to_others == false) + continue; + + SendChatMessage(client->peer_id, line); + } } } else @@ -2580,6 +2676,7 @@ core::list<PlayerInfo> Server::getPlayerInfo() return list; } + void Server::peerAdded(con::Peer *peer) { DSTACK(__FUNCTION_NAME); @@ -3020,6 +3117,8 @@ void Server::SendBlocks(float dtime) JMutexAutoLock envlock(m_env_mutex); + //TimeTaker timer("Server::SendBlocks"); + core::array<PrioritySortedBlockTransfer> queue; s32 total_sending = 0; @@ -3087,6 +3186,39 @@ RemoteClient* Server::getClient(u16 peer_id) return n->getValue(); } +std::wstring Server::getStatusString() +{ + std::wostringstream os(std::ios_base::binary); + os<<L"# Server: "; + // Uptime + os<<L"uptime="<<m_uptime.get(); + // Information about clients + os<<L", clients={"; + for(core::map<u16, RemoteClient*>::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + // Get client and check that it is valid + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + // Get player + Player *player = m_env.getPlayer(client->peer_id); + // Get name of player + std::wstring name = L"unknown"; + if(player != NULL) + name = narrow_to_wide(player->getName()); + // Add name to information string + os<<name<<L","; + } + os<<L"}"; + if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false) + os<<" WARNING: Map saving is disabled."<<std::endl; + return os.str(); +} + + void setCreativeInventory(Player *player) { player->resetInventory(); @@ -3455,11 +3587,11 @@ void Server::handlePeerChanges() } } -void dedicated_server_loop(Server &server) +void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); - std::cout<<std::endl; + std::cout<<DTIME<<std::endl; std::cout<<"========================"<<std::endl; std::cout<<"Running dedicated server"<<std::endl; std::cout<<"========================"<<std::endl; @@ -3472,6 +3604,12 @@ void dedicated_server_loop(Server &server) sleep_ms(30); server.step(0.030); + if(server.getShutdownRequested() || kill) + { + std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl; + break; + } + static int counter = 0; counter--; if(counter <= 0) diff --git a/src/server.h b/src/server.h index d19a440d7..9582c99dd 100644 --- a/src/server.h +++ b/src/server.h @@ -390,15 +390,11 @@ public: void Receive(); void ProcessData(u8 *data, u32 datasize, u16 peer_id); - /*void Send(u16 peer_id, u16 channelnum, - SharedBuffer<u8> data, bool reliable);*/ - - // Environment and Connection must be locked when called + // Environment and Connection must be locked when called void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver); - // Environment and Connection must be locked when called - //void SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver); - + // + core::list<PlayerInfo> getPlayerInfo(); u32 getDayNightRatio() @@ -412,7 +408,12 @@ public: else return 1000; } - + + bool getShutdownRequested() + { + return m_shutdown_requested.get(); + } + private: // Virtual methods from con::PeerHandler. @@ -432,7 +433,10 @@ private: // When called, connection mutex should be locked RemoteClient* getClient(u16 peer_id); - + + // Connection must be locked when called + std::wstring getStatusString(); + /* Get a player from memory or creates one. If player is already connected, return NULL @@ -490,7 +494,7 @@ private: float m_time_of_day_send_timer; MutexedVariable<double> m_uptime; - + enum PeerChangeType { PEER_ADDED, @@ -508,14 +512,18 @@ private: std::string m_mapsavedir; + MutexedVariable<bool> m_shutdown_requested; + friend class EmergeThread; friend class RemoteClient; }; /* - Runs a simple dedicated server loop + Runs a simple dedicated server loop. + + Shuts down when run is set to false. */ -void dedicated_server_loop(Server &server); +void dedicated_server_loop(Server &server, bool &run); #endif diff --git a/src/servermain.cpp b/src/servermain.cpp index 1c301d4f5..254b1f28a 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -98,7 +98,6 @@ std::ostream *derr_server_ptr = &dstream; std::ostream *dout_client_ptr = &dstream; std::ostream *derr_client_ptr = &dstream; - /* gettime.h implementation */ @@ -129,6 +128,9 @@ int main(int argc, char *argv[]) DSTACK(__FUNCTION_NAME); + porting::signal_handler_init(); + bool &kill = *porting::signal_handler_killstatus(); + porting::initializePaths(); initializeMaterialProperties(); @@ -251,6 +253,11 @@ int main(int argc, char *argv[]) srand(time(0)); mysrand(time(0)); + // Initialize stuff + + init_mapnode(); + init_mineral(); + /* Run unit tests */ @@ -260,11 +267,6 @@ int main(int argc, char *argv[]) run_tests(); } - // Initialize stuff - - init_mapnode(); - init_mineral(); - /* Check parameters */ @@ -308,9 +310,9 @@ int main(int argc, char *argv[]) // Create server Server server(map_dir.c_str()); server.start(port); - + // Run server - dedicated_server_loop(server); + dedicated_server_loop(server, kill); } //try catch(con::PeerNotFoundException &e) diff --git a/src/test.cpp b/src/test.cpp index e5b22a978..1de902787 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -192,7 +192,7 @@ struct TestMapNode // Transparency n.d = CONTENT_AIR; assert(n.light_propagates() == true); - n.d = 0; + n.d = CONTENT_STONE; assert(n.light_propagates() == false); } }; diff --git a/src/utility.h b/src/utility.h index 46277cd42..8c81aba91 100644 --- a/src/utility.h +++ b/src/utility.h @@ -802,9 +802,15 @@ struct ValueSpec class Settings { public: + Settings() + { + m_mutex.Init(); + } void writeLines(std::ostream &os) { + JMutexAutoLock lock(m_mutex); + for(core::map<std::string, std::string>::Iterator i = m_settings.getIterator(); i.atEnd() == false; i++) @@ -817,6 +823,8 @@ public: bool parseConfigLine(const std::string &line) { + JMutexAutoLock lock(m_mutex); + std::string trimmedline = trim(line); // Ignore comments @@ -899,6 +907,8 @@ public: core::list<std::string> &dst, core::map<std::string, bool> &updated) { + JMutexAutoLock lock(m_mutex); + if(is.eof()) return false; @@ -981,6 +991,8 @@ public: } } + JMutexAutoLock lock(m_mutex); + // Write stuff back { std::ofstream os(filename); @@ -1087,21 +1099,29 @@ public: void set(std::string name, std::string value) { + JMutexAutoLock lock(m_mutex); + m_settings[name] = value; } void setDefault(std::string name, std::string value) { + JMutexAutoLock lock(m_mutex); + m_defaults[name] = value; } bool exists(std::string name) { + JMutexAutoLock lock(m_mutex); + return (m_settings.find(name) || m_defaults.find(name)); } std::string get(std::string name) { + JMutexAutoLock lock(m_mutex); + core::map<std::string, std::string>::Node *n; n = m_settings.find(name); if(n == NULL) @@ -1139,7 +1159,7 @@ public: bool getBoolAsk(std::string name, std::string question, bool def) { // If it is in settings - if(m_settings.find(name)) + if(exists(name)) return getBool(name); std::string s; @@ -1167,7 +1187,7 @@ public: u16 getU16Ask(std::string name, std::string question, u16 def) { // If it is in settings - if(m_settings.find(name)) + if(exists(name)) return getU16(name); std::string s; @@ -1238,12 +1258,17 @@ public: void clear() { + JMutexAutoLock lock(m_mutex); + m_settings.clear(); m_defaults.clear(); } Settings & operator+=(Settings &other) { + JMutexAutoLock lock(m_mutex); + JMutexAutoLock lock2(other.m_mutex); + if(&other == this) return *this; @@ -1267,6 +1292,9 @@ public: Settings & operator=(Settings &other) { + JMutexAutoLock lock(m_mutex); + JMutexAutoLock lock2(other.m_mutex); + if(&other == this) return *this; @@ -1279,6 +1307,8 @@ public: private: core::map<std::string, std::string> m_settings; core::map<std::string, std::string> m_defaults; + // All methods that access m_settings/m_defaults directly should lock this. + JMutex m_mutex; }; /* |