Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / stdin_monitor_thread.cpp
blob6e213c9881f14233730ce446e58adeb767241c4f
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //-----------------------------------------------------------------------------
18 // includes
19 //-----------------------------------------------------------------------------
21 #include "stdnet.h"
23 #include "nel/misc/common.h"
24 #include "nel/misc/thread.h"
25 #include "nel/misc/command.h"
27 #include "stdin_monitor_thread.h"
30 //-----------------------------------------------------------------------------
31 // namespace: NLNET
32 //-----------------------------------------------------------------------------
34 namespace NLNET
37 //-----------------------------------------------------------------------------
38 // class CStdinMonitorThread
39 //-----------------------------------------------------------------------------
41 class CStdinMonitorThread : public NLMISC::IRunnable
43 public:
44 // ctor
45 CStdinMonitorThread();
47 // main routine executed when the thread is started
48 void run();
50 // interface for adding commands, retrieving commands and verifying whether there are commands waiting
51 void pushCommand(std::string nextCommand);
52 std::string popCommand();
53 bool commandWaiting() const;
55 private:
56 std::string _NextCommand;
57 volatile bool _CommandWaiting;
61 //-----------------------------------------------------------------------------
62 // methods CStdinMonitorThread
63 //-----------------------------------------------------------------------------
65 CStdinMonitorThread::CStdinMonitorThread()
67 _CommandWaiting= false;
70 void CStdinMonitorThread::run ()
72 while(!feof(stdin))
74 // wait for the main thread to deal with the previous command
75 while (commandWaiting())
77 NLMISC::nlSleep(1);
80 // get the next command from the command line
81 char theCommand[1024] = "";
82 if (!fgets(theCommand, sizeofarray(theCommand), stdin))
84 nlwarning("fgets failed");
85 break;
88 // push the command to allow reader thread to deal with it
89 pushCommand(theCommand);
93 void CStdinMonitorThread::pushCommand(std::string nextCommand)
95 // wait for the previous command to be treated
96 while (_CommandWaiting)
98 NLMISC::nlSleep(1);
101 // copy the next command into the appropriate buffer
102 _NextCommand= nextCommand;
104 while (!_NextCommand.empty()
105 && (_NextCommand[_NextCommand.size()-1] == '\n'
106 || _NextCommand[_NextCommand.size()-1] == '\r'))
108 _NextCommand = _NextCommand.substr(0, _NextCommand.size()-1);
111 // set the _CommandWaiting flag, to allow reader thread to treat the new command
112 _CommandWaiting= true;
115 std::string CStdinMonitorThread::popCommand()
117 // wait for a command to be ligned up (waiting)
118 while (!_CommandWaiting)
122 // copy out the next command
123 std::string result= _NextCommand;
125 // clear out the next command variable ready for its next use
126 _NextCommand.clear();
128 // clear the _CommandWaiting flag, to allow writer thread to add a new command
129 _CommandWaiting= false;
131 // all done so return the command
132 return result;
135 bool CStdinMonitorThread::commandWaiting() const
137 return _CommandWaiting;
141 //-----------------------------------------------------------------------------
142 // class CStdinMonitorSingleton
143 //-----------------------------------------------------------------------------
145 class CStdinMonitorSingleton: public IStdinMonitorSingleton
147 public:
148 // static for getting hold of the singleton instance
149 static CStdinMonitorSingleton* getInstance();
151 // methods required by IStdinMonitorSingleton
152 void init();
153 void update();
154 void release();
156 private:
157 // this is a singleton so dissallow construction from outside...
158 CStdinMonitorSingleton();
159 CStdinMonitorSingleton(const CStdinMonitorSingleton&);
160 CStdinMonitorSingleton& operator =(const CStdinMonitorSingleton&);
162 private:
163 // data for the singleton instance
164 CStdinMonitorThread* _StdinMonitorThreadInstance;
165 NLMISC::IThread* _StdinMonitorThreadHandle;
169 //-----------------------------------------------------------------------------
170 // methods IStdinMonitorSingleton
171 //-----------------------------------------------------------------------------
173 IStdinMonitorSingleton* IStdinMonitorSingleton::getInstance()
175 return CStdinMonitorSingleton::getInstance();
179 //-----------------------------------------------------------------------------
180 // methods CStdinMonitorSingleton
181 //-----------------------------------------------------------------------------
183 CStdinMonitorSingleton* CStdinMonitorSingleton::getInstance()
185 static CStdinMonitorSingleton* instance= NULL;
186 if (instance==NULL)
187 instance= new CStdinMonitorSingleton;
188 return instance;
191 void CStdinMonitorSingleton::init()
193 _StdinMonitorThreadInstance= new CStdinMonitorThread;
194 _StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance, 1024*4*4);
195 _StdinMonitorThreadHandle->start();
198 void CStdinMonitorSingleton::update()
200 // if we're not initialised yet then return
201 if (_StdinMonitorThreadInstance== NULL)
202 return;
204 // if there's a command waiting then treat it (not more than one command per visit)
205 if (_StdinMonitorThreadInstance->commandWaiting())
207 std::string nextCommand= _StdinMonitorThreadInstance->popCommand();
208 if (!nextCommand.empty())
210 NLMISC::ICommand::execute(nextCommand,*NLMISC::InfoLog);
215 void CStdinMonitorSingleton::release()
217 // if we've never been initialised or we've already been released thent there's nothing more to do...
218 if (_StdinMonitorThreadInstance== NULL)
219 return;
221 // terminate the thread and wait for it to finish
222 _StdinMonitorThreadHandle->terminate();
223 _StdinMonitorThreadHandle->wait();
225 // destroy the thread object instance and reset the pointer to NULL to mark as 'uninitialised'
226 delete _StdinMonitorThreadInstance;
227 _StdinMonitorThreadInstance= NULL;
230 CStdinMonitorSingleton::CStdinMonitorSingleton()
232 _StdinMonitorThreadHandle= NULL;
233 _StdinMonitorThreadInstance= NULL;
236 CStdinMonitorSingleton::CStdinMonitorSingleton(const CStdinMonitorSingleton&)
238 _StdinMonitorThreadHandle= NULL;
239 _StdinMonitorThreadInstance= NULL;
242 CStdinMonitorSingleton& CStdinMonitorSingleton::operator =(const CStdinMonitorSingleton&)
244 return *this;
247 } // NLNET