// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //----------------------------------------------------------------------------- // includes //----------------------------------------------------------------------------- #include "stdnet.h" #include "nel/misc/common.h" #include "nel/misc/thread.h" #include "nel/misc/command.h" #include "stdin_monitor_thread.h" //----------------------------------------------------------------------------- // namespace: NLNET //----------------------------------------------------------------------------- namespace NLNET { //----------------------------------------------------------------------------- // class CStdinMonitorThread //----------------------------------------------------------------------------- class CStdinMonitorThread : public NLMISC::IRunnable { public: // ctor CStdinMonitorThread(); // main routine executed when the thread is started void run(); // interface for adding commands, retrieving commands and verifying whether there are commands waiting void pushCommand(std::string nextCommand); std::string popCommand(); bool commandWaiting() const; private: std::string _NextCommand; volatile bool _CommandWaiting; }; //----------------------------------------------------------------------------- // methods CStdinMonitorThread //----------------------------------------------------------------------------- CStdinMonitorThread::CStdinMonitorThread() { _CommandWaiting= false; } void CStdinMonitorThread::run () { while(!feof(stdin)) { // wait for the main thread to deal with the previous command while (commandWaiting()) { NLMISC::nlSleep(1); } // get the next command from the command line char theCommand[1024] = ""; if (!fgets(theCommand, sizeofarray(theCommand), stdin)) { nlwarning("fgets failed"); break; } // push the command to allow reader thread to deal with it pushCommand(theCommand); } } void CStdinMonitorThread::pushCommand(std::string nextCommand) { // wait for the previous command to be treated while (_CommandWaiting) { NLMISC::nlSleep(1); } // copy the next command into the appropriate buffer _NextCommand= nextCommand; while (!_NextCommand.empty() && (_NextCommand[_NextCommand.size()-1] == '\n' || _NextCommand[_NextCommand.size()-1] == '\r')) { _NextCommand = _NextCommand.substr(0, _NextCommand.size()-1); } // set the _CommandWaiting flag, to allow reader thread to treat the new command _CommandWaiting= true; } std::string CStdinMonitorThread::popCommand() { // wait for a command to be ligned up (waiting) while (!_CommandWaiting) { } // copy out the next command std::string result= _NextCommand; // clear out the next command variable ready for its next use _NextCommand.clear(); // clear the _CommandWaiting flag, to allow writer thread to add a new command _CommandWaiting= false; // all done so return the command return result; } bool CStdinMonitorThread::commandWaiting() const { return _CommandWaiting; } //----------------------------------------------------------------------------- // class CStdinMonitorSingleton //----------------------------------------------------------------------------- class CStdinMonitorSingleton: public IStdinMonitorSingleton { public: // static for getting hold of the singleton instance static CStdinMonitorSingleton* getInstance(); // methods required by IStdinMonitorSingleton void init(); void update(); void release(); private: // this is a singleton so dissallow construction from outside... CStdinMonitorSingleton(); CStdinMonitorSingleton(const CStdinMonitorSingleton&); CStdinMonitorSingleton& operator =(const CStdinMonitorSingleton&); private: // data for the singleton instance CStdinMonitorThread* _StdinMonitorThreadInstance; NLMISC::IThread* _StdinMonitorThreadHandle; }; //----------------------------------------------------------------------------- // methods IStdinMonitorSingleton //----------------------------------------------------------------------------- IStdinMonitorSingleton* IStdinMonitorSingleton::getInstance() { return CStdinMonitorSingleton::getInstance(); } //----------------------------------------------------------------------------- // methods CStdinMonitorSingleton //----------------------------------------------------------------------------- CStdinMonitorSingleton* CStdinMonitorSingleton::getInstance() { static CStdinMonitorSingleton* instance= NULL; if (instance==NULL) instance= new CStdinMonitorSingleton; return instance; } void CStdinMonitorSingleton::init() { _StdinMonitorThreadInstance= new CStdinMonitorThread; _StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance, 1024*4*4); _StdinMonitorThreadHandle->start(); } void CStdinMonitorSingleton::update() { // if we're not initialised yet then return if (_StdinMonitorThreadInstance== NULL) return; // if there's a command waiting then treat it (not more than one command per visit) if (_StdinMonitorThreadInstance->commandWaiting()) { std::string nextCommand= _StdinMonitorThreadInstance->popCommand(); if (!nextCommand.empty()) { NLMISC::ICommand::execute(nextCommand,*NLMISC::InfoLog); } } } void CStdinMonitorSingleton::release() { // if we've never been initialised or we've already been released thent there's nothing more to do... if (_StdinMonitorThreadInstance== NULL) return; // terminate the thread and wait for it to finish _StdinMonitorThreadHandle->terminate(); _StdinMonitorThreadHandle->wait(); // destroy the thread object instance and reset the pointer to NULL to mark as 'uninitialised' delete _StdinMonitorThreadInstance; _StdinMonitorThreadInstance= NULL; } CStdinMonitorSingleton::CStdinMonitorSingleton() { _StdinMonitorThreadHandle= NULL; _StdinMonitorThreadInstance= NULL; } CStdinMonitorSingleton::CStdinMonitorSingleton(const CStdinMonitorSingleton&) { _StdinMonitorThreadHandle= NULL; _StdinMonitorThreadInstance= NULL; } CStdinMonitorSingleton& CStdinMonitorSingleton::operator =(const CStdinMonitorSingleton&) { return *this; } } // NLNET