diff --git a/CMakeLists.txt b/CMakeLists.txt index 2484d6eb10..21507680f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,12 +30,12 @@ set(GAMEREND_HEADER apps/openmw/mwrender/interior.hpp apps/openmw/mwrender/playerpos.hpp apps/openmw/mwrender/sky.hpp) -source_group(game_renderer FILES ${GAMEREND} ${GAMEREND_HEADER}) +source_group(apps\\openmw\\mwrender FILES ${GAMEREND} ${GAMEREND_HEADER}) # set(GAMEINPUT) set(GAMEINPUT_HEADER apps/openmw/mwinput/inputmanager.hpp) -source_group(game_input FILES ${GAMEINPUT} ${GAMEINPUT_HEADER}) +source_group(apps\\openmw\\mwinput FILES ${GAMEINPUT} ${GAMEINPUT_HEADER}) set(APPS ${GAME} ${GAMEREND} ${GAMEINPUT}) set(APPS_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER}) @@ -48,7 +48,7 @@ set(BSA set(BSA_HEADER components/bsa/bsa_archive.hpp components/bsa/bsa_file.hpp) -source_group(bsa FILES ${BSA} ${BSA_HEADER}) +source_group(components\\bsa FILES ${BSA} ${BSA_HEADER}) set(NIF components/nif/nif_file.cpp) @@ -64,13 +64,13 @@ set(NIF_HEADER components/nif/data.hpp components/nif/nif_file.hpp components/nif/property.hpp) -source_group(nif FILES ${NIF} ${NIF_HEADER}) +source_group(components\\nif FILES ${NIF} ${NIF_HEADER}) set(NIFOGRE components/nifogre/ogre_nif_loader.cpp) set(NIFOGRE_HEADER components/nifogre/ogre_nif_loader.hpp) -source_group(nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER}) +source_group(components\\nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER}) set(ESM_STORE components/esm_store/store.cpp @@ -79,16 +79,16 @@ set(ESM_STORE_HEADER components/esm_store/cell_store.hpp components/esm_store/reclists.hpp components/esm_store/store.hpp) -source_group(esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER}) +source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER}) file(GLOB ESM_HEADER components/esm/*.hpp) -source_group(esm_header FILES ${ESM_HEADER}) +source_group(components\\esm FILES ${ESM_HEADER}) set(OGRE components/engine/ogre/renderer.cpp) set(OGRE_HEADER components/engine/ogre/renderer.hpp) -source_group(ogre FILES ${OGRE} ${OGRE_HEADER}) +source_group(components\\engine\\ogre FILES ${OGRE} ${OGRE_HEADER}) set(INPUT components/engine/input/oismanager.cpp) @@ -99,7 +99,13 @@ set(INPUT_HEADER components/engine/input/dispatch_map.hpp components/engine/input/dispatcher.hpp components/engine/input/poller.hpp) -source_group(input FILES ${INPUT} ${INPUT_HEADER}) +source_group(components\\engine\\input FILES ${INPUT} ${INPUT_HEADER}) + +set(COMMANDSERVER + components/commandserver/command.hpp + components/commandserver/server.hpp + components/commandserver/server.cpp) +source_group(components\\commandserver FILES ${COMMANDSERVER}) set(MISC components/misc/stringops.cpp @@ -107,19 +113,21 @@ set(MISC set(MISC_HEADER components/misc/fileops.hpp components/misc/slice_array.hpp - components/misc/stringops.hpp) -source_group(misc FILES ${MISC} ${MISC_HEADER}) + components/misc/stringops.hpp + components/misc/tsdeque.hpp) +source_group(components\\misc FILES ${MISC} ${MISC_HEADER}) file(GLOB COMPILER components/compiler/*.cpp) file(GLOB COMPILER_HEADER components/compiler/*.hpp) -source_group(compiler FILES ${COMPILER} ${COMPILER_HEADER}) +source_group(components\\compiler FILES ${COMPILER} ${COMPILER_HEADER}) file(GLOB INTERPRETER components/interpreter/*.cpp) file(GLOB INTERPRETER_HEADER components/interpreter/*.hpp) -source_group(interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER}) - +source_group(components\\interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER}) -set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC} ${COMPILER} +set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC} + ${COMMANDSERVER} + ${COMPILER} ${INTERPRETER}) set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER} ${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER} ${COMPILER_HEADER} @@ -128,7 +136,7 @@ set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_ # source directory: libs set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp) -source_group(mangle_vfs FILES ${MANGLE_VFS}) +source_group(libs\\mangle_vfs FILES ${MANGLE_VFS}) set(OPENMW_LIBS ${MANGLE_VFS}) set(OPENMW_LIBS_HEADER) @@ -151,7 +159,7 @@ include_directories("." ${CMAKE_HOME_DIRECTORY}/extern/caelum/include) link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR}) -ADD_SUBDIRECTORY( extern/caelum ) +add_subdirectory( extern/caelum ) # Specify build paths @@ -203,6 +211,9 @@ if (APPLE) target_link_libraries(openmw ${CARBON_FRAMEWORK}) endif (APPLE) +# Other apps and tools +add_subdirectory( apps/clientconsole ) + # Apple bundling if (APPLE) set_source_files_properties( @@ -220,19 +231,11 @@ endif (APPLE) # Tools option(BUILD_MWCOMPILER "build standalone Morrowind script compiler" ON) - if (BUILD_MWCOMPILER) -set(TOOLS_MWCOMPILER ${COMPILER} apps/mwcompiler/main.cpp apps/mwcompiler/context.cpp - apps/mwcompiler/context.hpp) - -add_executable(mwcompiler ${TOOLS_MWCOMPILER}) + add_subdirectory( apps/mwcompiler ) endif() option(BUILD_MWINTERPRETER "build standalone Morrowind script code interpreter" ON) - if (BUILD_MWINTERPRETER) -set(TOOLS_MWINTERPRETER ${INTERPRETER} apps/mwinterpreter/main.cpp - apps/mwinterpreter/context.cpp apps/mwinterpreter/context.hpp) - -add_executable(mwinterpreter ${TOOLS_MWINTERPRETER}) + add_subdirectory( apps/mwinterpreter ) endif() diff --git a/apps/clientconsole/CMakeLists.txt b/apps/clientconsole/CMakeLists.txt new file mode 100755 index 0000000000..702fbbf8a5 --- /dev/null +++ b/apps/clientconsole/CMakeLists.txt @@ -0,0 +1,2 @@ +project(clientconsole) +add_executable(clientconsole client.cpp) diff --git a/apps/clientconsole/client.cpp b/apps/clientconsole/client.cpp new file mode 100755 index 0000000000..d7d93e0306 --- /dev/null +++ b/apps/clientconsole/client.cpp @@ -0,0 +1,138 @@ +#include +#include +#include + +using boost::asio::ip::tcp; + +#pragma warning( disable : 4966 ) + +class Client +{ +protected: + struct Header + { + char magic[4]; + boost::uint32_t dataLength; + }; + + boost::asio::io_service mIOService; + tcp::socket* mpSocket; + +public: + + bool connect(const char* port) + { + tcp::resolver resolver(mIOService); + tcp::resolver::query query("localhost", port); + tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); + tcp::resolver::iterator end; + + mpSocket = new tcp::socket(mIOService); + boost::system::error_code error = boost::asio::error::host_not_found; + while (error && endpoint_iterator != end) + { + mpSocket->close(); + mpSocket->connect(*endpoint_iterator++, error); + } + + return (error) ? false : true; + } + void disconnect() + { + mpSocket->close(); + mIOService.stop(); + } + + bool send (const char* msg) + { + const size_t slen = strlen(msg); + const size_t plen = sizeof(Header) + slen + 1; + + std::vector packet(plen); + Header* pHeader = reinterpret_cast(&packet[0]); + strncpy(pHeader->magic, "OMW0", 4); + pHeader->dataLength = slen + 1; // Include the null terminator + strncpy(&packet[8], msg, pHeader->dataLength); + + boost::system::error_code ec; + boost::asio::write(*mpSocket, boost::asio::buffer(packet), + boost::asio::transfer_all(), ec); + if (ec) + std::cout << "Error: " << ec.message() << std::endl; + + return !ec; + } + + bool receive (std::string& reply) + { + Header header; + boost::system::error_code error; + mpSocket->read_some(boost::asio::buffer(&header, sizeof(Header)), error); + + if (error != boost::asio::error::eof) + { + if (strncmp(header.magic, "OMW0", 4) == 0) + { + std::vector msg; + msg.resize(header.dataLength); + + boost::system::error_code error; + mpSocket->read_some(boost::asio::buffer(&msg[0], header.dataLength), error); + if (!error) + { + reply = &msg[0]; + return true; + } + } + else + throw std::exception("Unexpected header!"); + } + return false; + } +}; + + +int main(int argc, char* argv[]) +{ + std::cout << "OpenMW client console" << std::endl; + std::cout << "=====================" << std::endl; + std::cout << "Type 'quit' to exit." << std::endl; + std::cout << "Connecting..."; + + Client client; + if (client.connect("27917")) + { + std::cout << "success." << std::endl; + + bool bDone = false; + do + { + std::cout << "Client> "; + std::string buffer; + std::getline(std::cin, buffer); + + if (buffer == "quit") + bDone = true; + else + { + if (client.send(buffer.c_str())) + { + std::string reply; + if (client.receive(reply)) + std::cout << "Server: " << reply << std::endl; + else + bDone = true; + } + else + bDone = true; + } + + } while (!bDone); + + client.disconnect(); + } + else + std::cout << "failed." << std::endl; + + return 0; +} diff --git a/apps/mwcompiler/CMakeLists.txt b/apps/mwcompiler/CMakeLists.txt new file mode 100644 index 0000000000..b2243f255b --- /dev/null +++ b/apps/mwcompiler/CMakeLists.txt @@ -0,0 +1,9 @@ +project(MWCompiler) + +set(TOOLS_MWCOMPILER ${COMPILER} + main.cpp + context.cpp + context.hpp) + +add_executable(mwcompiler ${TOOLS_MWCOMPILER}) + diff --git a/apps/mwinterpreter/CMakeLists.txt b/apps/mwinterpreter/CMakeLists.txt new file mode 100644 index 0000000000..0789256577 --- /dev/null +++ b/apps/mwinterpreter/CMakeLists.txt @@ -0,0 +1,9 @@ +project(MWInterpreter) + +set(TOOLS_MWINTERPRETER + ${INTERPRETER} + main.cpp + context.cpp + context.hpp) + +add_executable(mwinterpreter ${TOOLS_MWINTERPRETER}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 82e1ff58f2..fd8f70d1ee 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -11,8 +11,24 @@ #include "world.hpp" +class ProcessCommandsHook : public Ogre::FrameListener +{ +public: + ProcessCommandsHook(OMW::Engine* pEngine) : mpEngine (pEngine) {} + virtual bool frameStarted(const Ogre::FrameEvent& evt) + { + mpEngine->processCommands(); + return true; + } +protected: + OMW::Engine* mpEngine; +}; + + OMW::Engine::Engine() { + mspCommandServer.reset( + new OMW::CommandServer::Server(&mCommandQueue, kCommandServerPort)); } // Load all BSA files in data directory. @@ -71,6 +87,31 @@ void OMW::Engine::addMaster (const std::string& master) } } +<<<<<<< HEAD +======= +// Enables sky rendering +// +void OMW::Engine::enableSky (bool bEnable) +{ + mEnableSky = bEnable; +} + +void OMW::Engine::processCommands() +{ + Command cmd; + while (mCommandQueue.try_pop_front(cmd)) + { + ///\todo Add actual processing of the received command strings + std::cout << "Command: '" << cmd.mCommand << "'" << std::endl; + + ///\todo Replace with real output. For now, echo back the string in uppercase + std::string reply(cmd.mCommand); + std::transform(reply.begin(), reply.end(), reply.begin(), toupper); + cmd.mReplyFunction(reply); + } +} + +>>>>>>> 450542b4b9a7cf6987c192abbf7e2cc44da286d2 // Initialise and enter main loop. void OMW::Engine::go() @@ -106,11 +147,22 @@ void OMW::Engine::go() // Sets up the input system MWInput::MWInputManager input(mOgre, mWorld->getPlayerPos()); + // Launch the console server + std::cout << "Starting command server on port " << kCommandServerPort << std::endl; + mspCommandServer->start(); + mOgre.getRoot()->addFrameListener( new ProcessCommandsHook(this) ); + std::cout << "\nStart! Press Q/ESC or close window to exit.\n"; // Start the main rendering loop mOgre.start(); +<<<<<<< HEAD +======= + mspCommandServer->stop(); + delete mpSkyManager; + +>>>>>>> 450542b4b9a7cf6987c192abbf7e2cc44da286d2 std::cout << "\nThat's all for now!\n"; } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index ec9fb82d25..8395474378 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -6,6 +6,16 @@ #include #include "components/engine/ogre/renderer.hpp" +#include "apps/openmw/mwrender/mwscene.hpp" +#include "components/misc/tsdeque.hpp" +#include "components/commandserver/server.hpp" +#include "components/commandserver/command.hpp" + + +namespace MWRender +{ + class SkyManager; +} namespace OMW { @@ -15,12 +25,20 @@ namespace OMW class Engine { + enum { kCommandServerPort = 27917 }; + boost::filesystem::path mDataDir; Render::OgreRenderer mOgre; std::string mCellName; std::string mMaster; World *mWorld; + bool mEnableSky; + MWRender::SkyManager* mpSkyManager; + + TsDeque mCommandQueue; + std::auto_ptr mspCommandServer; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); @@ -49,6 +67,12 @@ namespace OMW /// - Currently OpenMW only supports one master at the same time. void addMaster (const std::string& master); + /// Enables rendering of the sky (off by default). + void enableSky (bool bEnable); + + /// Process pending commands + void processCommands(); + /// Initialise and enter main loop. void go(); }; diff --git a/components/commandserver/command.hpp b/components/commandserver/command.hpp new file mode 100755 index 0000000000..128b87697a --- /dev/null +++ b/components/commandserver/command.hpp @@ -0,0 +1,19 @@ +#ifndef COMMANDSERVER_COMMAND_HPP +#define COMMANDSERVER_COMMAND_HPP + +namespace OMW +{ + /// + /// A Command is currently defined as a string input that, when processed, + /// will generate a string output. The string output is passed to the + /// mReplyFunction as soon as the command has been processed. + /// + class Command + { + public: + std::string mCommand; + boost::function1 mReplyFunction; + }; +} + +#endif COMMANDSERVER_COMMAND_HPP diff --git a/components/commandserver/server.cpp b/components/commandserver/server.cpp new file mode 100755 index 0000000000..7b9198e0b1 --- /dev/null +++ b/components/commandserver/server.cpp @@ -0,0 +1,199 @@ + +#include "server.hpp" + +using boost::asio::ip::tcp; + +// +// Namespace for containing implementation details that the +// rest of OpenMW doesn't need to worry about +// +namespace OMW { namespace CommandServer { namespace Detail { + + struct Header + { + char magic[4]; + size_t dataLength; + } header; + + /// + /// Tracks an active connection to the CommandServer + /// + class Connection + { + public: + Connection (boost::asio::io_service& io_service, Server* pServer); + + void start(); + void stop(); + + tcp::socket& socket(); + void reply (std::string s); + + protected: + void handle (); + + tcp::socket mSocket; + Server* mpServer; + boost::thread* mpThread; + }; + + Connection::Connection (boost::asio::io_service& io_service, Server* pServer) + : mSocket (io_service) + , mpServer (pServer) + { + } + + void Connection::start() + { + mpThread = new boost::thread(boost::bind(&Connection::handle, this)); + } + + /// + /// Stops and disconnects the connection + /// + void Connection::stop() + { + mSocket.close(); + mpThread->join(); + } + + tcp::socket& Connection::socket() + { + return mSocket; + } + + void Connection::reply (std::string reply) + { + const size_t plen = sizeof(Header) + reply.length() + 1; + + std::vector packet(plen); + Header* pHeader = reinterpret_cast(&packet[0]); + strncpy(pHeader->magic, "OMW0", 4); + pHeader->dataLength = reply.length() + 1; // Include the null terminator + strncpy(&packet[8], reply.c_str(), pHeader->dataLength); + + boost::system::error_code ec; + boost::asio::write(mSocket, boost::asio::buffer(packet), + boost::asio::transfer_all(), ec); + if (ec) + std::cout << "Error: " << ec.message() << std::endl; + } + + void Connection::handle () + { + bool bDone = false; + while (!bDone) + { + // Read the header + boost::system::error_code error; + mSocket.read_some(boost::asio::buffer(&header, sizeof(Header)), error); + + if (error != boost::asio::error::eof) + { + if (strncmp(header.magic, "OMW0", 4) == 0) + { + std::vector msg; + msg.resize(header.dataLength); + + boost::system::error_code error; + mSocket.read_some(boost::asio::buffer(&msg[0], header.dataLength), error); + if (!error) + mpServer->postCommand(this, &msg[0]); + else + bDone = true; + } + else + throw std::exception("Unexpected header!"); + } + else + bDone = true; + } + mpServer->removeConnection(this); + } + +}}} + +namespace OMW { namespace CommandServer { + + using namespace Detail; + + Server::Server (Deque* pCommandQueue, const int port) + : mAcceptor (mIOService, tcp::endpoint(tcp::v4(), port)) + , mpCommandQueue (pCommandQueue) + , mbStopping (false) + { + } + + + void Server::start() + { + mIOService.run(); + mpThread = new boost::thread(boost::bind(&Server::threadMain, this)); + } + + void Server::stop() + { + // (1) Stop accepting new connections + // (2) Wait for the listener thread to finish + mAcceptor.close(); + mpThread->join(); + + // Now that no new connections are possible, close any existing + // open connections + { + boost::mutex::scoped_lock lock(mConnectionsMutex); + mbStopping = true; + for (ConnectionSet::iterator it = mConnections.begin(); + it != mConnections.end(); + ++it) + { + (*it)->stop(); + } + } + } + + void Server::removeConnection (Connection* ptr) + { + // If the server is shutting down (rather the client closing the + // connection), don't remove the connection from the list: that + // would corrupt the iterator the server is using to shutdown all + // clients. + if (!mbStopping) + { + boost::mutex::scoped_lock lock(mConnectionsMutex); + std::set::iterator it = mConnections.find(ptr); + if (it != mConnections.end()) + mConnections.erase(it); + } + delete ptr; + } + + void Server::postCommand (Connection* pConnection, const char* s) + { + Command cmd; + cmd.mCommand = s; + cmd.mReplyFunction = std::bind1st(std::mem_fun(&Connection::reply), pConnection); + mpCommandQueue->push_back(cmd); + } + + void Server::threadMain() + { + // Loop until accept() fails, which will cause the break statement to be hit + while (true) + { + std::auto_ptr spConnection(new Connection(mAcceptor.io_service(), this)); + boost::system::error_code ec; + mAcceptor.accept(spConnection->socket(), ec); + if (!ec) + { + boost::mutex::scoped_lock lock(mConnectionsMutex); + mConnections.insert(spConnection.get()); + spConnection->start(); + spConnection.release(); + } + else + break; + } + } + +}} diff --git a/components/commandserver/server.hpp b/components/commandserver/server.hpp new file mode 100755 index 0000000000..b53e0f23a9 --- /dev/null +++ b/components/commandserver/server.hpp @@ -0,0 +1,63 @@ +#ifndef CONSOLESERVER_H +#define CONSOLESERVER_H + +#include +#include +#include +#include +#include +#include + +#include "components/misc/tsdeque.hpp" +#include "components/commandserver/command.hpp" + +namespace OMW { namespace CommandServer +{ + // + // Forward Declarations + // + namespace Detail + { + class Connection; + } + + // + // Server that opens a port to listen for string commands which will be + // put into the deque provided in the Server constructor. + // + class Server + { + public: + typedef TsDeque Deque; + + Server (Deque* pCommandQueue, const int port); + + void start(); + void stop(); + + protected: + friend class Detail::Connection; + typedef std::set ConnectionSet; + + void removeConnection (Detail::Connection* ptr); + void postCommand (Detail::Connection*, const char* s); + + void threadMain(); + + // Objects used to set up the listening server + boost::asio::io_service mIOService; + boost::asio::ip::tcp::acceptor mAcceptor; + boost::thread* mpThread; + bool mbStopping; + + // Track active connections + ConnectionSet mConnections; + mutable boost::mutex mConnectionsMutex; + + // Pointer to command queue + Deque* mpCommandQueue; + }; + +}} + +#endif // CONSOLESERVER_H diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 658e9334af..2d932bedef 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "generator.hpp" #include "scanner.hpp" diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 2c76865891..ff5bf33ee6 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "errorhandler.hpp" #include "exception.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index e4869cba5a..f0001fe85d 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "exception.hpp" #include "errorhandler.hpp" diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 3654d209b8..d0f8107db9 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -195,7 +195,7 @@ namespace Interpreter mSegment5.insert (std::make_pair (code, opcode)); } - void Interpreter::Interpreter::run (const Type_Code *code, int codeSize) + void Interpreter::run (const Type_Code *code, int codeSize) { assert (codeSize>=4); diff --git a/components/misc/tsdeque.hpp b/components/misc/tsdeque.hpp new file mode 100755 index 0000000000..88b2ce001c --- /dev/null +++ b/components/misc/tsdeque.hpp @@ -0,0 +1,56 @@ +#ifndef TSDEQUE_H +#define TSDEQUE_H + +#include + +// +// Adapted from http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html +// +template +class TsDeque +{ +private: + std::deque the_queue; + mutable boost::mutex the_mutex; + boost::condition_variable the_condition_variable; + +public: + void push_back(Data const& data) + { + boost::mutex::scoped_lock lock(the_mutex); + the_queue.push_back(data); + lock.unlock(); + the_condition_variable.notify_one(); + } + + bool empty() const + { + boost::mutex::scoped_lock lock(the_mutex); + return the_queue.empty(); + } + + bool try_pop_front(Data& popped_value) + { + boost::mutex::scoped_lock lock(the_mutex); + if(the_queue.empty()) + return false; + + popped_value=the_queue.front(); + the_queue.pop_front(); + return true; + } + + void wait_and_pop_front(Data& popped_value) + { + boost::mutex::scoped_lock lock(the_mutex); + while(the_queue.empty()) + { + the_condition_variable.wait(lock); + } + + popped_value=the_queue.front(); + the_queue.pop_front(); + } +}; + +#endif // TSDEQUE_H