From c2c0442c73aae0404561295f54a84550acd22a99 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Tue, 20 Mar 2012 19:59:06 -0300 Subject: [PATCH 1/9] First step with multithreaded runs --- src/Server/Queue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Server/Queue.cpp b/src/Server/Queue.cpp index 4f2b9cd..6628edd 100644 --- a/src/Server/Queue.cpp +++ b/src/Server/Queue.cpp @@ -2,6 +2,7 @@ #include "Queue.h" #include "Command.h" #include "Utils.h" +#include using boost::lexical_cast; @@ -70,11 +71,10 @@ void Queue::run() { else if (now >= cmd.last_execution + cmd.interval) { echo("Running '" << cmd.line() << "'"); - cmd.run(); + boost::thread runner(boost::bind(&Command::run, cmd)); time(&cmd.last_execution); echo(cmd.response); - } _commands[cmd.line()] = cmd; From 6c25945c5b644b2d81f06b60bd633e490d26ea90 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Tue, 20 Mar 2012 21:49:33 -0300 Subject: [PATCH 2/9] Finished multithread version --- src/Common/Command.cpp | 22 +--------------- src/Common/Command.h | 2 +- src/Server/Queue.cpp | 60 ++++++++++++++++++++++++++++++++---------- src/Server/Queue.h | 3 ++- src/Server/Server.cpp | 4 +-- src/Server/stdafx.h | 1 + 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/Common/Command.cpp b/src/Common/Command.cpp index 8a31096..7d8299c 100644 --- a/src/Common/Command.cpp +++ b/src/Common/Command.cpp @@ -4,6 +4,7 @@ using std::string; Command::Command() { + is_running = false; time(&last_execution); time(&last_request); } @@ -12,24 +13,3 @@ string Command::line() { return executable + " " + arguments; } -void Command::run() { - - char psBuffer[128]; - FILE *iopipe; - - iopipe = _popen(line().c_str(), "r"); - - if (iopipe == NULL) { - response = "[CGI4LCD] Error running..."; - } - else { - response = ""; - - while(!feof(iopipe)) { - if(fgets(psBuffer, 128, iopipe) != NULL) { - response += string(psBuffer); - } - } - _pclose(iopipe); - } -} diff --git a/src/Common/Command.h b/src/Common/Command.h index 8390893..a824924 100644 --- a/src/Common/Command.h +++ b/src/Common/Command.h @@ -20,10 +20,10 @@ class Command { bool is_internal; bool do_not_queue; bool add_and_run; + bool is_running; Command(); string line(); - void run(); }; #endif // COMMAND_H diff --git a/src/Server/Queue.cpp b/src/Server/Queue.cpp index 6628edd..fa667de 100644 --- a/src/Server/Queue.cpp +++ b/src/Server/Queue.cpp @@ -2,14 +2,13 @@ #include "Queue.h" #include "Command.h" #include "Utils.h" -#include using boost::lexical_cast; Queue::Queue(boost::asio::io_service& io_service) : _timer(io_service, boost::posix_time::seconds(1)) { - _timer.async_wait(boost::bind(&Queue::run, this)); + _timer.async_wait(boost::bind(&Queue::process, this)); } @@ -26,7 +25,7 @@ void Queue::add(Command &cmd) { _commands[cmd.line()] = cmd; if (cmd.add_and_run) { - _commands[cmd.line()].run(); + run(cmd); } } else { @@ -34,13 +33,13 @@ void Queue::add(Command &cmd) { } } -void Queue::run() { +void Queue::process() { map::iterator it; Command cmd; _timer.expires_at(_timer.expires_at() + boost::posix_time::seconds(1)); - _timer.async_wait(boost::bind(&Queue::run, this)); + _timer.async_wait(boost::bind(&Queue::process, this)); #ifdef DEBUG int queue_size = _commands.size(); @@ -66,15 +65,10 @@ void Queue::run() { echo("Erasing '" << cmd.line() << "'"); _commands.erase(it); - continue; + break; } - else if (now >= cmd.last_execution + cmd.interval) { - echo("Running '" << cmd.line() << "'"); - - boost::thread runner(boost::bind(&Command::run, cmd)); - time(&cmd.last_execution); - - echo(cmd.response); + else if (cmd.is_running == false && now >= cmd.last_execution + cmd.interval) { + boost::thread runner(boost::bind(&Queue::run, this, cmd)); } _commands[cmd.line()] = cmd; @@ -84,4 +78,42 @@ void Queue::run() { Command Queue::get(const string &line) { return _commands[line]; -} \ No newline at end of file +} + +void Queue::run(Command &command) { + + char psBuffer[128]; + FILE *iopipe; + + echo("Running '" << command.line() << "'"); + + if (!command.do_not_queue) { + _commands[command.line()].is_running = true; + } + + iopipe = _popen(command.line().c_str(), "r"); + + if (iopipe == NULL) { + command.response = "[CGI4LCD] Error running..."; + } + else { + string response = ""; + + while(!feof(iopipe)) { + if(fgets(psBuffer, 128, iopipe) != NULL) { + response += string(psBuffer); + } + } + + _pclose(iopipe); + time(&command.last_execution); + command.response = response; + } + + echo("Runner response: '" << command.response << "'"); + + if (!command.do_not_queue) { + _commands[command.line()].is_running = false; + _commands[command.line()] = command; + } +} diff --git a/src/Server/Queue.h b/src/Server/Queue.h index 37655ca..392099b 100644 --- a/src/Server/Queue.h +++ b/src/Server/Queue.h @@ -12,7 +12,8 @@ class Queue { Queue(boost::asio::io_service& io_service); void add(Command &cmd); - void run(); + void process(); + void run(Command &command); Command get(const string& line); private: diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index e8d5a59..e16f423 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -24,15 +24,15 @@ void Server::handle_receive_from(const boost::system::error_code& error, size_t cmd = Protocol::parse(temp); if (!cmd.is_malformed) { + if (cmd.do_not_queue) { - cmd.run(); + _queue.run(cmd); } else { _queue.add(cmd); cmd = _queue.get(cmd.line()); } - echo("Response: '" << cmd.response << "'"); } // else: malformed packet. nothing to do diff --git a/src/Server/stdafx.h b/src/Server/stdafx.h index 48ca6ec..d61945f 100644 --- a/src/Server/stdafx.h +++ b/src/Server/stdafx.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef DEBUG #define echo(str) std::cout << str << std::endl; From 3c0ce0f825b844e56cc5875d04acd07d0791ddf0 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Tue, 20 Mar 2012 21:53:32 -0300 Subject: [PATCH 3/9] Version bump --- src/Plugin/Plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/Plugin.cpp b/src/Plugin/Plugin.cpp index c192b22..be1fbd2 100644 --- a/src/Plugin/Plugin.cpp +++ b/src/Plugin/Plugin.cpp @@ -59,6 +59,6 @@ __stdcall function3(char *param1, char *param2) extern "C" DLLEXPORT char * __stdcall function20(char *param1, char *param2) { - return "cgi.dll is part of CGI4LCD version 0.1 by MendelGusmao github.com/MendelGusmao"; + return "cgi.dll is part of CGI4LCD version 0.2 by MendelGusmao github.com/MendelGusmao"; } From c9af80ca6e274cf62411d668bd103b522e801751 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Tue, 20 Mar 2012 21:54:46 -0300 Subject: [PATCH 4/9] Version bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d378da..6ebe4bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -CGI FOR LCD SMARTIE 0.1-alpha +CGI FOR LCD SMARTIE 0.2-alpha ============================= > CGI for LCD Smartie is designed to be a fast gateway between LCD Smartie ([http://lcdsmartie.sourceforge.net](http://lcdsmartie.sourceforge.net)) and language From a3f8eebc29f1326ae902868953be143a15085bb7 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Wed, 21 Mar 2012 13:05:48 -0300 Subject: [PATCH 5/9] Implemented 'max_threads' configuration --- src/Server/Queue.cpp | 12 +++++++++--- src/Server/Queue.h | 4 +++- src/Server/Server.cpp | 4 ++-- src/Server/Server.h | 2 +- src/Server/main.cpp | 3 ++- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Server/Queue.cpp b/src/Server/Queue.cpp index fa667de..006a944 100644 --- a/src/Server/Queue.cpp +++ b/src/Server/Queue.cpp @@ -5,8 +5,10 @@ using boost::lexical_cast; -Queue::Queue(boost::asio::io_service& io_service) : - _timer(io_service, boost::posix_time::seconds(1)) { +Queue::Queue(boost::asio::io_service& io_service, unsigned int max_threads) : + _timer(io_service, boost::posix_time::seconds(1)), + _max_threads(max_threads), + _running_threads(0) { _timer.async_wait(boost::bind(&Queue::process, this)); @@ -67,7 +69,7 @@ void Queue::process() { _commands.erase(it); break; } - else if (cmd.is_running == false && now >= cmd.last_execution + cmd.interval) { + else if (_running_threads < _max_threads && cmd.is_running == false && now >= cmd.last_execution + cmd.interval) { boost::thread runner(boost::bind(&Queue::run, this, cmd)); } @@ -87,6 +89,8 @@ void Queue::run(Command &command) { echo("Running '" << command.line() << "'"); + ++_running_threads; + if (!command.do_not_queue) { _commands[command.line()].is_running = true; } @@ -116,4 +120,6 @@ void Queue::run(Command &command) { _commands[command.line()].is_running = false; _commands[command.line()] = command; } + + --_running_threads; } diff --git a/src/Server/Queue.h b/src/Server/Queue.h index 392099b..31ca3f7 100644 --- a/src/Server/Queue.h +++ b/src/Server/Queue.h @@ -10,7 +10,7 @@ class Queue { public: - Queue(boost::asio::io_service& io_service); + Queue(boost::asio::io_service& io_service, unsigned int max_threads); void add(Command &cmd); void process(); void run(Command &command); @@ -20,6 +20,8 @@ class Queue { boost::asio::deadline_timer _timer; map _commands; + unsigned int _max_threads; + unsigned int _running_threads; }; diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index e16f423..ee69934 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -6,10 +6,10 @@ using namespace std; -Server::Server(boost::asio::io_service& io_service, short port) : +Server::Server(boost::asio::io_service& io_service, short port, unsigned int max_threads) : _io_service(io_service), _socket(io_service, udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port)), - _queue(io_service) + _queue(io_service, max_threads) { receive(); diff --git a/src/Server/Server.h b/src/Server/Server.h index 433a5cb..1b2b957 100644 --- a/src/Server/Server.h +++ b/src/Server/Server.h @@ -18,7 +18,7 @@ class Server enum { max_length = 1024 }; char _data[max_length]; - Server(boost::asio::io_service& io_service, short port); + Server(boost::asio::io_service& io_service, short port, unsigned int max_threads); void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd); void handle_send_to(const boost::system::error_code& error, size_t bytes_sent); void receive(); diff --git a/src/Server/main.cpp b/src/Server/main.cpp index b31b1e8..83f8dfd 100644 --- a/src/Server/main.cpp +++ b/src/Server/main.cpp @@ -8,6 +8,7 @@ int main(int argc, char* argv[]) { string ini_file(Utils::app_path() + "\\..\\scripts\\cgi4lcd.ini"); unsigned int port = lexical_cast(Utils::ini_read(ini_file, "cgi4lcd.port", "65432")); + unsigned int max_threads = lexical_cast(Utils::ini_read(ini_file, "cgi4lcd.max_threads", "4")); #ifndef DEBUG HWND hWnd = GetConsoleWindow(); @@ -16,7 +17,7 @@ int main(int argc, char* argv[]) { try { boost::asio::io_service io_service; - Server s(io_service, port); + Server s(io_service, port, max_threads); io_service.run(); } catch (std::exception& e) { From 5d1a2e20de3f0c858c1fd6a309147da4117f6c23 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Wed, 21 Mar 2012 13:09:04 -0300 Subject: [PATCH 6/9] Adding 'max_threads' diretive to ini file --- scripts/cgi4lcd.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/cgi4lcd.ini b/scripts/cgi4lcd.ini index eef7427..67ff3f8 100644 --- a/scripts/cgi4lcd.ini +++ b/scripts/cgi4lcd.ini @@ -5,6 +5,7 @@ refresh=1 port=65432 default_extension="php" add_and_run=1 +max_threads=4 [php] language="PHP" From 3bdc4d97335fb7ca1ef4f36dc9ac55a3de461704 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Wed, 21 Mar 2012 13:53:42 -0300 Subject: [PATCH 7/9] Making the code look a little bit better --- src/Common/Protocol.cpp | 42 ++++++++++++++++++++--------------------- src/Common/Protocol.h | 2 +- src/Plugin/Client.cpp | 16 ++++++++-------- src/Server/Queue.cpp | 38 ++++++++++++++++++------------------- src/Server/Queue.h | 2 +- src/Server/Server.cpp | 18 +++++++++--------- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/Common/Protocol.cpp b/src/Common/Protocol.cpp index ebdbd2c..8a8c1b8 100644 --- a/src/Common/Protocol.cpp +++ b/src/Common/Protocol.cpp @@ -8,48 +8,48 @@ using boost::algorithm::split; Command Protocol::parse(const string &data) { vector packet; - Command cmd; + Command command; split(packet, data, boost::is_any_of(PROTOCOL_DELIMITER)); if (packet.size() != PROTOCOL_EXPECTED_SIZE) { - cmd.is_malformed = true; + command.is_malformed = true; } else { if (packet[0] != PROTOCOL_HEADER) { - cmd.is_malformed = true; + command.is_malformed = true; } else if (packet[1] == "command" && packet[2] != "") { - cmd.is_internal = true; - cmd.executable = packet[1]; - cmd.arguments = packet[2]; + command.is_internal = true; + command.executable = packet[2]; + command.arguments = packet[3]; } else { - cmd.executable = packet[1]; - cmd.arguments = packet[2]; - cmd.interval = lexical_cast(packet[3]); - cmd.timeout = lexical_cast(packet[4]); - cmd.do_not_queue = packet[5] == "1"; - cmd.add_and_run = packet[6] == "1"; - cmd.is_malformed = false; + command.executable = packet[1]; + command.arguments = packet[2]; + command.interval = lexical_cast(packet[3]); + command.timeout = lexical_cast(packet[4]); + command.do_not_queue = packet[5] == "1"; + command.add_and_run = packet[6] == "1"; + command.is_malformed = false; } } - return cmd; + return command; } -string Protocol::build(const Command &cmd) { +string Protocol::build(const Command &command) { vector packet; packet.push_back(PROTOCOL_HEADER); - packet.push_back(cmd.executable); - packet.push_back(cmd.arguments); - packet.push_back(lexical_cast(cmd.interval)); - packet.push_back(lexical_cast(cmd.timeout)); - packet.push_back(cmd.do_not_queue ? "1" : "0"); - packet.push_back(cmd.add_and_run ? "1" : "0"); + packet.push_back(command.executable); + packet.push_back(command.arguments); + packet.push_back(lexical_cast(command.interval)); + packet.push_back(lexical_cast(command.timeout)); + packet.push_back(command.do_not_queue ? "1" : "0"); + packet.push_back(command.add_and_run ? "1" : "0"); packet.push_back(""); return join(packet, PROTOCOL_DELIMITER); diff --git a/src/Common/Protocol.h b/src/Common/Protocol.h index 86ae975..4d744be 100644 --- a/src/Common/Protocol.h +++ b/src/Common/Protocol.h @@ -15,7 +15,7 @@ class Protocol { public: static Command parse(const string &data); - static string build(const Command &cmd); + static string build(const Command &command); }; diff --git a/src/Plugin/Client.cpp b/src/Plugin/Client.cpp index e4acf90..730e97a 100644 --- a/src/Plugin/Client.cpp +++ b/src/Plugin/Client.cpp @@ -93,13 +93,13 @@ string Client::request(const string &interpreter, const string &arguments, unsig using boost::asio::ip::udp; - Command cmd; - cmd.executable = interpreter; - cmd.arguments = arguments; - cmd.interval = interval; - cmd.timeout = timeout; - cmd.do_not_queue = do_not_queue; - cmd.add_and_run = _add_and_run; + Command command; + command.executable = interpreter; + command.arguments = arguments; + command.interval = interval; + command.timeout = timeout; + command.do_not_queue = do_not_queue; + command.add_and_run = _add_and_run; string buffer(""); @@ -111,7 +111,7 @@ string Client::request(const string &interpreter, const string &arguments, unsig udp::socket socket(io_service); socket.open(udp::v4()); - string data = Protocol::build(cmd); + string data = Protocol::build(command); const char* send_buf = data.c_str(); socket.send_to(boost::asio::buffer(send_buf, data.size()), receiver_endpoint); diff --git a/src/Server/Queue.cpp b/src/Server/Queue.cpp index 006a944..3e629a5 100644 --- a/src/Server/Queue.cpp +++ b/src/Server/Queue.cpp @@ -14,31 +14,31 @@ Queue::Queue(boost::asio::io_service& io_service, unsigned int max_threads) : } -void Queue::add(Command &cmd) { +void Queue::add(Command &command) { - map::iterator it = _commands.find(cmd.line()); + map::iterator it = _commands.find(command.line()); time_t now; time(&now); if (it == _commands.end()) { - cmd.response = ""; - cmd.last_request = now; + command.response = ""; + command.last_request = now; - _commands[cmd.line()] = cmd; + _commands[command.line()] = command; - if (cmd.add_and_run) { - run(cmd); + if (command.add_and_run) { + run(command); } } else { - _commands[cmd.line()].last_request = now; + _commands[command.line()].last_request = now; } } void Queue::process() { map::iterator it; - Command cmd; + Command command; _timer.expires_at(_timer.expires_at() + boost::posix_time::seconds(1)); _timer.async_wait(boost::bind(&Queue::process, this)); @@ -53,27 +53,27 @@ void Queue::process() { #endif for (it = _commands.begin(); it != _commands.end(); ++it) { - cmd = it->second; + command = it->second; time_t now; time(&now); - echo("Command '" << cmd.line() << "'"); - echo("Cleanup Time: " << cmd.last_request << " + " << cmd.timeout); - echo("Next Execution: " << cmd.last_execution << " + " << cmd.interval); - echo("Cached Response: '" << cmd.response << "'"); + echo("Command '" << command.line() << "'"); + echo("Cleanup Time: " << command.last_request << " + " << command.timeout); + echo("Next Execution: " << command.last_execution << " + " << command.interval); + echo("Cached Response: '" << command.response << "'"); - if (now >= cmd.last_request + cmd.timeout) { - echo("Erasing '" << cmd.line() << "'"); + if (now >= command.last_request + command.timeout) { + echo("Erasing '" << command.line() << "'"); _commands.erase(it); break; } - else if (_running_threads < _max_threads && cmd.is_running == false && now >= cmd.last_execution + cmd.interval) { - boost::thread runner(boost::bind(&Queue::run, this, cmd)); + else if (_running_threads < _max_threads && command.is_running == false && now >= command.last_execution + command.interval) { + boost::thread runner(boost::bind(&Queue::run, this, command)); } - _commands[cmd.line()] = cmd; + _commands[command.line()] = command; } } diff --git a/src/Server/Queue.h b/src/Server/Queue.h index 31ca3f7..d59615f 100644 --- a/src/Server/Queue.h +++ b/src/Server/Queue.h @@ -11,7 +11,7 @@ class Queue { public: Queue(boost::asio::io_service& io_service, unsigned int max_threads); - void add(Command &cmd); + void add(Command &command); void process(); void run(Command &command); Command get(const string& line); diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index ee69934..0e59b54 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -19,28 +19,28 @@ Server::Server(boost::asio::io_service& io_service, short port, unsigned int max void Server::handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd) { if (!error && bytes_recvd > 0) { - Command cmd; + Command command; string temp(_data, bytes_recvd); - cmd = Protocol::parse(temp); + command = Protocol::parse(temp); - if (!cmd.is_malformed) { + if (!command.is_malformed) { - if (cmd.do_not_queue) { - _queue.run(cmd); + if (command.do_not_queue) { + _queue.run(command); } else { - _queue.add(cmd); - cmd = _queue.get(cmd.line()); + _queue.add(command); + command = _queue.get(command.line()); } } // else: malformed packet. nothing to do char response[max_length]; - strcpy_s(response, cmd.response.c_str()); + strcpy_s(response, command.response.c_str()); _socket.async_send_to( - boost::asio::buffer(response, cmd.response.size()), + boost::asio::buffer(response, command.response.size()), _sender_endpoint, boost::bind( &Server::handle_send_to, From 008a857ddbea561b516c88c63a7e12ccff9c7305 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Wed, 21 Mar 2012 15:17:16 -0300 Subject: [PATCH 8/9] Avoiding needless atribution --- src/Server/Queue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Server/Queue.cpp b/src/Server/Queue.cpp index 3e629a5..91a3bd0 100644 --- a/src/Server/Queue.cpp +++ b/src/Server/Queue.cpp @@ -110,7 +110,6 @@ void Queue::run(Command &command) { } _pclose(iopipe); - time(&command.last_execution); command.response = response; } @@ -118,7 +117,8 @@ void Queue::run(Command &command) { if (!command.do_not_queue) { _commands[command.line()].is_running = false; - _commands[command.line()] = command; + _commands[command.line()].response = command.response; + time(&_commands[command.line()].last_execution); } --_running_threads; From b5ae66f820acea5af69e6d7ab0cb9bc2c0184489 Mon Sep 17 00:00:00 2001 From: MendelGusmao Date: Wed, 21 Mar 2012 15:45:49 -0300 Subject: [PATCH 9/9] Updating README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ebe4bd..660c495 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,10 @@ CONFIGURING > The default file extension to be considered by the plugin if not specified in the filename passed to $dll > * add_and_run (boolean, 0-1) -> If the value is 1, the server will execute the command right after it is added to the queue. If not, the server will await the configured interval to run the command and will be returning an empty response until it happens. +> If the value is 1, the server will execute the command right after it is added to the queue. If not, the server will await the configured interval to run the command and will be returning an empty response until it happens. + +> * max_threads (numeric) +> The maximum number of commands that can be run simultaneously > The subsequent sections are named with the common file extension of the language. They have the following attributes: