[Cmake-commits] CMake branch, next, updated. v3.8.0-rc4-724-gd2132c5
Kitware Robot
kwrobot at kitware.com
Mon Apr 10 10:15:03 EDT 2017
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".
The branch, next has been updated
discards 253c0670dd346bd0e8b0486011f7f8d917aa3036 (commit)
via d2132c55af0d318ff663f358cfe4cd94f2f0525c (commit)
via 5e27782e3e5ec5bbbc235b3f477ad93db1d64def (commit)
via 23fccf30b01bb59c18ce2c8ac5a924ce5f2bcab5 (commit)
via a1c198d2639cf07bece19e45ccdd00ff51193574 (commit)
via 1f7764b96f554a11a896ff565b1d8fd7fba65b9f (commit)
via 94420a7b61d6c83dbd2ba0ce566af6624cd07aad (commit)
via 282a68451bda6c4a0e18cb6f7375cecf65531f5e (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (253c0670dd346bd0e8b0486011f7f8d917aa3036)
\
N -- N -- N (d2132c55af0d318ff663f358cfe4cd94f2f0525c)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d2132c55af0d318ff663f358cfe4cd94f2f0525c
commit d2132c55af0d318ff663f358cfe4cd94f2f0525c
Merge: 5e27782 a1c198d
Author: Brad King <brad.king at kitware.com>
AuthorDate: Mon Apr 10 14:07:15 2017 +0000
Commit: Kitware Robot <kwrobot at kitware.com>
CommitDate: Mon Apr 10 10:07:19 2017 -0400
Stage topic 'server-refactor'
Topic-id: 22877
Topic-url: https://gitlab.kitware.com/cmake/cmake/merge_requests/552
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5e27782e3e5ec5bbbc235b3f477ad93db1d64def
commit 5e27782e3e5ec5bbbc235b3f477ad93db1d64def
Merge: 23fccf3 9d15d3c
Author: Brad King <brad.king at kitware.com>
AuthorDate: Mon Apr 10 13:48:41 2017 +0000
Commit: Kitware Robot <kwrobot at kitware.com>
CommitDate: Mon Apr 10 10:06:11 2017 -0400
Stage topic 'FindPythonInterp-3.6-windows'
Topic-id: 23545
Topic-url: https://gitlab.kitware.com/cmake/cmake/merge_requests/675
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a1c198d2639cf07bece19e45ccdd00ff51193574
commit a1c198d2639cf07bece19e45ccdd00ff51193574
Author: Justin Berger <j.david.berger at gmail.com>
AuthorDate: Sat Feb 25 15:06:34 2017 -0700
Commit: Justin Berger <j.david.berger at gmail.com>
CommitDate: Sat Apr 8 12:28:51 2017 -0600
Added support for connections that aren't event based
diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx
index 132d5e4..1bd3858 100644
--- a/Source/cmConnection.cxx
+++ b/Source/cmConnection.cxx
@@ -14,18 +14,19 @@ struct write_req_t
uv_buf_t buf;
};
-void cmConnection::on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
- uv_buf_t* buf)
+void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf)
{
(void)(handle);
char* rawBuffer = new char[suggested_size];
*buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
}
-void cmConnection::on_read(uv_stream_t* stream, ssize_t nread,
- const uv_buf_t* buf)
+void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
{
- auto conn = reinterpret_cast<cmConnection*>(stream->data);
+ auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data);
if (nread >= 0) {
conn->ReadData(std::string(buf->base, buf->base + nread));
} else {
@@ -35,19 +36,19 @@ void cmConnection::on_read(uv_stream_t* stream, ssize_t nread,
delete[](buf->base);
}
-void cmConnection::on_close_delete(uv_handle_t* handle)
+void cmEventBasedConnection::on_close_delete(uv_handle_t* handle)
{
delete handle;
}
-void cmConnection::on_close(uv_handle_t*)
+void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/)
{
}
-void cmConnection::on_write(uv_write_t* req, int status)
+void cmEventBasedConnection::on_write(uv_write_t* req, int status)
{
(void)(status);
- auto conn = reinterpret_cast<cmConnection*>(req->data);
+ auto conn = reinterpret_cast<cmEventBasedConnection*>(req->data);
// Free req and buffer
write_req_t* wr = reinterpret_cast<write_req_t*>(req);
@@ -57,19 +58,19 @@ void cmConnection::on_write(uv_write_t* req, int status)
conn->ProcessNextRequest();
}
-void cmConnection::on_new_connection(uv_stream_t* stream, int status)
+void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status)
{
(void)(status);
- auto conn = reinterpret_cast<cmConnection*>(stream->data);
+ auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data);
conn->Connect(stream);
}
-bool cmConnection::IsOpen() const
+bool cmEventBasedConnection::IsOpen() const
{
return this->WriteStream != 0;
}
-void cmConnection::WriteData(const std::string& data)
+void cmEventBasedConnection::WriteData(const std::string& data)
{
assert(this->WriteStream);
@@ -84,12 +85,7 @@ void cmConnection::WriteData(const std::string& data)
on_write);
}
-cmConnection::~cmConnection()
-{
- OnServerShuttingDown();
-}
-
-void cmConnection::ReadData(const std::string& data)
+void cmEventBasedConnection::ReadData(const std::string& data)
{
this->RawReadBuffer += data;
if (BufferStrategy) {
@@ -105,6 +101,34 @@ void cmConnection::ReadData(const std::string& data)
}
}
+cmEventBasedConnection::cmEventBasedConnection(
+ cmConnectionBufferStrategy* bufferStrategy)
+ : BufferStrategy(bufferStrategy)
+{
+}
+
+void cmEventBasedConnection::Connect(uv_stream_t* server)
+{
+ (void)server;
+ Server->OnConnected(nullptr);
+}
+
+void cmEventBasedConnection::OnDisconnect(int onerror)
+{
+ (void)onerror;
+ this->Server->OnDisconnect(this);
+}
+
+cmConnection::~cmConnection()
+{
+ OnServerShuttingDown();
+}
+
+bool cmConnection::OnServerShuttingDown()
+{
+ return true;
+}
+
void cmConnection::ProcessNextRequest()
{
if (this->Queue.empty()) {
@@ -121,16 +145,6 @@ void cmConnection::SetServer(cmServerBase* s)
Server = s;
}
-cmConnection::cmConnection(cmConnectionBufferStrategy* bufferStrategy)
- : BufferStrategy(bufferStrategy)
-{
-}
-
-void cmConnection::Connect(uv_stream_t*)
-{
- Server->OnConnected(nullptr);
-}
-
void cmConnection::QueueRequest(const std::string& request)
{
this->Queue.push_back(request);
@@ -142,14 +156,3 @@ bool cmConnection::OnServeStart(std::string* errString)
(void)errString;
return true;
}
-
-bool cmConnection::OnServerShuttingDown()
-{
- return true;
-}
-
-void cmConnection::OnDisconnect(int errorCode)
-{
- (void)errorCode;
- this->Server->OnDisconnect(this);
-}
diff --git a/Source/cmConnection.h b/Source/cmConnection.h
index d477769..74c25a7 100644
--- a/Source/cmConnection.h
+++ b/Source/cmConnection.h
@@ -44,51 +44,61 @@ public:
// TODO: There should be a callback / flag set for errors
};
+class cmConnection
+{
+public:
+ virtual void WriteData(const std::string& data) = 0;
+
+ virtual ~cmConnection();
+
+ virtual bool OnServerShuttingDown();
+
+ virtual bool IsOpen() const = 0;
+
+ virtual void ProcessNextRequest();
+
+ virtual void SetServer(cmServerBase* s);
+
+ virtual void QueueRequest(const std::string& request);
+
+ virtual bool OnServeStart(std::string* pString);
+
+protected:
+ std::deque<std::string> Queue;
+
+ cmServerBase* Server = 0;
+};
+
/***
* Abstraction of a connection; ties in event callbacks from libuv and notifies
* the server when appropriate
*/
-class cmConnection
+class cmEventBasedConnection : public cmConnection
{
public:
- virtual ~cmConnection();
-
/***
* @param bufferStrategy If no strategy is given, it will process the raw
* chunks as they come in. The connection
* owns the pointer given.
*/
- cmConnection(cmConnectionBufferStrategy* bufferStrategy = 0);
+ cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = 0);
virtual void Connect(uv_stream_t* server);
virtual void ReadData(const std::string& data);
- virtual bool OnServeStart(std::string* errString);
-
- virtual bool OnServerShuttingDown();
-
- virtual bool IsOpen() const;
+ virtual bool IsOpen() const override;
- virtual void WriteData(const std::string& data);
-
- virtual void QueueRequest(const std::string& request);
-
- virtual void ProcessNextRequest();
-
- virtual void SetServer(cmServerBase* s);
+ virtual void WriteData(const std::string& data) override;
virtual void OnDisconnect(int errorCode);
uv_stream_t* ReadStream = nullptr;
- cmServerBase* Server = 0;
uv_stream_t* WriteStream = nullptr;
static void on_close(uv_handle_t* handle);
static void on_close_delete(uv_handle_t* handle);
protected:
- std::deque<std::string> Queue;
-
std::string RawReadBuffer;
std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy;
diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx
index 7796574..2d5781b 100644
--- a/Source/cmPipeConnection.cxx
+++ b/Source/cmPipeConnection.cxx
@@ -7,7 +7,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */
cmPipeConnection::cmPipeConnection(const std::string& name,
cmConnectionBufferStrategy* bufferStrategy)
- : cmConnection(bufferStrategy)
+ : cmEventBasedConnection(bufferStrategy)
, PipeName(name)
{
}
@@ -26,8 +26,7 @@ void cmPipeConnection::Connect(uv_stream_t* server)
this->ClientPipe = new uv_pipe_t();
uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0);
- this->ClientPipe->data = static_cast<cmConnection*>(this);
-
+ this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this);
auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
if (uv_accept(server, client) != 0) {
uv_close(reinterpret_cast<uv_handle_t*>(client), &on_close_delete);
@@ -45,7 +44,7 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage)
{
this->ServerPipe = new uv_pipe_t();
uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0);
- this->ServerPipe->data = static_cast<cmConnection*>(this);
+ this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this);
int r;
if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h
index f0a3aca..db0c273 100644
--- a/Source/cmPipeConnection.h
+++ b/Source/cmPipeConnection.h
@@ -9,7 +9,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */
#include <string>
#include <vector>
-class cmPipeConnection : public cmConnection
+class cmPipeConnection : public cmEventBasedConnection
{
public:
cmPipeConnection(const std::string& name,
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 7f8f061..257ac93 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -40,7 +40,7 @@ static void on_walk_to_shutdown(uv_handle_t* handle, void* arg)
{
(void)arg;
if (!uv_is_closing(handle))
- uv_close(handle, &cmConnection::on_close);
+ uv_close(handle, &cmEventBasedConnection::on_close);
}
class cmServer::DebugInfo
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index cdd1584..6c4a2c5 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -10,7 +10,7 @@
cmStdIoConnection::cmStdIoConnection(
cmConnectionBufferStrategy* bufferStrategy)
- : cmConnection(bufferStrategy)
+ : cmEventBasedConnection(bufferStrategy)
{
}
@@ -22,23 +22,23 @@ void cmStdIoConnection::SetServer(cmServerBase* s)
usesTty = true;
uv_tty_init(this->Server->GetLoop(), &this->Input.tty, 0, 1);
uv_tty_set_mode(&this->Input.tty, UV_TTY_MODE_NORMAL);
- Input.tty.data = static_cast<cmConnection*>(this);
+ Input.tty.data = static_cast<cmEventBasedConnection*>(this);
this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.tty);
uv_tty_init(this->Server->GetLoop(), &this->Output.tty, 1, 0);
uv_tty_set_mode(&this->Output.tty, UV_TTY_MODE_NORMAL);
- Output.tty.data = static_cast<cmConnection*>(this);
+ Output.tty.data = static_cast<cmEventBasedConnection*>(this);
this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.tty);
} else {
usesTty = false;
uv_pipe_init(this->Server->GetLoop(), &this->Input.pipe, 0);
uv_pipe_open(&this->Input.pipe, 0);
- Input.pipe.data = static_cast<cmConnection*>(this);
+ Input.pipe.data = static_cast<cmEventBasedConnection*>(this);
this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.pipe);
uv_pipe_init(this->Server->GetLoop(), &this->Output.pipe, 0);
uv_pipe_open(&this->Output.pipe, 1);
- Output.pipe.data = static_cast<cmConnection*>(this);
+ Output.pipe.data = static_cast<cmEventBasedConnection*>(this);
this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.pipe);
}
}
diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h
index f7f4c17..bf8f602 100644
--- a/Source/cmServerConnection.h
+++ b/Source/cmServerConnection.h
@@ -35,7 +35,7 @@ private:
/***
* Generic connection over std io interfaces -- tty
*/
-class cmStdIoConnection : public cmConnection
+class cmStdIoConnection : public cmEventBasedConnection
{
public:
cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy);
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 24d1d50..2f80ee2 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -47,7 +47,7 @@ private:
Json::Value m_Data;
};
-class cmConnection;
+class cmEventBasedConnection;
class cmServerRequest
{
public:
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1f7764b96f554a11a896ff565b1d8fd7fba65b9f
commit 1f7764b96f554a11a896ff565b1d8fd7fba65b9f
Author: Justin Berger <j.david.berger at gmail.com>
AuthorDate: Fri Mar 24 21:57:04 2017 -0600
Commit: Justin Berger <j.david.berger at gmail.com>
CommitDate: Sat Apr 8 12:28:44 2017 -0600
Added connection as part of a server request
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 831a4cd..7f8f061 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -94,7 +94,7 @@ void cmServer::ProcessRequest(cmConnection* connection,
debug->PrintStatistics = debugValue["showStats"].asBool();
}
- const cmServerRequest request(this, value[kTYPE_KEY].asString(),
+ const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(),
value[kCOOKIE_KEY].asString(), value);
if (request.Type == "") {
@@ -336,7 +336,7 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min,
obj[kPROGRESS_MAXIMUM_KEY] = max;
obj[kPROGRESS_CURRENT_KEY] = current;
- this->WriteJsonObject(obj, nullptr);
+ this->WriteJsonObject(request.Connection, obj, nullptr);
}
void cmServer::WriteMessage(const cmServerRequest& request,
@@ -356,7 +356,7 @@ void cmServer::WriteMessage(const cmServerRequest& request,
obj[kTITLE_KEY] = title;
}
- WriteJsonObject(obj, nullptr);
+ WriteJsonObject(request.Connection, obj, nullptr);
}
void cmServer::WriteParseError(cmConnection* connection,
@@ -536,6 +536,7 @@ cmServerBase::~cmServerBase()
if (ServeThread.joinable())
ServeThread.join();
+ uv_loop_close(&Loop);
}
void cmServerBase::AddNewConnection(cmConnection* ownedConnection)
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 334a05a..34d0942 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -19,14 +19,15 @@
#include "cmServerDictionary.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmConnection.h"
#include "cm_jsoncpp_reader.h"
#include "cm_jsoncpp_value.h"
+
#endif
#include <algorithm>
+#include <fstream>
#include <string>
-#include <vector>
-
// Get rid of some windows macros:
#undef max
@@ -121,11 +122,13 @@ void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir,
} // namespace
-cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
- const std::string& c, const Json::Value& d)
+cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
+ const std::string& t, const std::string& c,
+ const Json::Value& d)
: Type(t)
, Cookie(c)
, Data(d)
+ , Connection(connection)
, m_Server(server)
{
}
@@ -1052,7 +1055,6 @@ cmServerResponse cmServerProtocol1_0::ProcessGlobalSettings(
// Currently used generator:
obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName;
obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName;
-
return request.Reply(obj);
}
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 027f145..24d1d50 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -6,11 +6,12 @@
#include "cmake.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmConnection.h"
#include "cm_jsoncpp_writer.h"
+
#endif
#include <memory>
-#include <string>
class cmake;
class cmFileMonitor;
@@ -46,6 +47,7 @@ private:
Json::Value m_Data;
};
+class cmConnection;
class cmServerRequest
{
public:
@@ -55,9 +57,11 @@ public:
const std::string Type;
const std::string Cookie;
const Json::Value Data;
+ cmConnection* Connection;
private:
- cmServerRequest(cmServer* server, const std::string& t, const std::string& c,
+ cmServerRequest(cmServer* server, cmConnection* connection,
+ const std::string& t, const std::string& c,
const Json::Value& d);
void ReportProgress(int min, int current, int max,
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=282a68451bda6c4a0e18cb6f7375cecf65531f5e
commit 282a68451bda6c4a0e18cb6f7375cecf65531f5e
Author: Justin Berger <j.david.berger at gmail.com>
AuthorDate: Fri Mar 24 21:38:52 2017 -0600
Commit: Justin Berger <j.david.berger at gmail.com>
CommitDate: Fri Mar 24 22:28:44 2017 -0600
Refactor of server components to make the event loop owned by server object
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 3b49f72..0a04848 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -993,7 +993,9 @@ target_link_libraries(cmake CMakeLib)
if(CMake_ENABLE_SERVER_MODE)
add_library(CMakeServerLib
+ cmConnection.h cmConnection.cxx
cmFileMonitor.cxx cmFileMonitor.h
+ cmPipeConnection.cxx cmPipeConnection.h
cmServer.cxx cmServer.h
cmServerConnection.cxx cmServerConnection.h
cmServerProtocol.cxx cmServerProtocol.h
diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx
new file mode 100644
index 0000000..132d5e4
--- /dev/null
+++ b/Source/cmConnection.cxx
@@ -0,0 +1,155 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmConnection.h"
+#include "cmServer.h"
+#include "cmServerConnection.h"
+#include "cm_uv.h"
+#include "string.h"
+#include <fstream>
+
+struct write_req_t
+{
+ uv_write_t req;
+ uv_buf_t buf;
+};
+
+void cmConnection::on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
+ uv_buf_t* buf)
+{
+ (void)(handle);
+ char* rawBuffer = new char[suggested_size];
+ *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
+}
+
+void cmConnection::on_read(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto conn = reinterpret_cast<cmConnection*>(stream->data);
+ if (nread >= 0) {
+ conn->ReadData(std::string(buf->base, buf->base + nread));
+ } else {
+ conn->OnDisconnect(nread);
+ }
+
+ delete[](buf->base);
+}
+
+void cmConnection::on_close_delete(uv_handle_t* handle)
+{
+ delete handle;
+}
+
+void cmConnection::on_close(uv_handle_t*)
+{
+}
+
+void cmConnection::on_write(uv_write_t* req, int status)
+{
+ (void)(status);
+ auto conn = reinterpret_cast<cmConnection*>(req->data);
+
+ // Free req and buffer
+ write_req_t* wr = reinterpret_cast<write_req_t*>(req);
+ delete[](wr->buf.base);
+ delete wr;
+
+ conn->ProcessNextRequest();
+}
+
+void cmConnection::on_new_connection(uv_stream_t* stream, int status)
+{
+ (void)(status);
+ auto conn = reinterpret_cast<cmConnection*>(stream->data);
+ conn->Connect(stream);
+}
+
+bool cmConnection::IsOpen() const
+{
+ return this->WriteStream != 0;
+}
+
+void cmConnection::WriteData(const std::string& data)
+{
+ assert(this->WriteStream);
+
+ auto ds = data.size();
+
+ write_req_t* req = new write_req_t;
+ req->req.data = this;
+ req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
+ memcpy(req->buf.base, data.c_str(), ds);
+ uv_write(reinterpret_cast<uv_write_t*>(req),
+ static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
+ on_write);
+}
+
+cmConnection::~cmConnection()
+{
+ OnServerShuttingDown();
+}
+
+void cmConnection::ReadData(const std::string& data)
+{
+ this->RawReadBuffer += data;
+ if (BufferStrategy) {
+ std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
+ do {
+ QueueRequest(packet);
+ packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
+ } while (!packet.empty());
+
+ } else {
+ QueueRequest(this->RawReadBuffer);
+ this->RawReadBuffer.clear();
+ }
+}
+
+void cmConnection::ProcessNextRequest()
+{
+ if (this->Queue.empty()) {
+ return;
+ }
+
+ const std::string input = this->Queue.front();
+ this->Queue.pop_front();
+ Server->ProcessRequest(this, input);
+}
+
+void cmConnection::SetServer(cmServerBase* s)
+{
+ Server = s;
+}
+
+cmConnection::cmConnection(cmConnectionBufferStrategy* bufferStrategy)
+ : BufferStrategy(bufferStrategy)
+{
+}
+
+void cmConnection::Connect(uv_stream_t*)
+{
+ Server->OnConnected(nullptr);
+}
+
+void cmConnection::QueueRequest(const std::string& request)
+{
+ this->Queue.push_back(request);
+ this->Server->NotifyDataQueued();
+}
+
+bool cmConnection::OnServeStart(std::string* errString)
+{
+ (void)errString;
+ return true;
+}
+
+bool cmConnection::OnServerShuttingDown()
+{
+ return true;
+}
+
+void cmConnection::OnDisconnect(int errorCode)
+{
+ (void)errorCode;
+ this->Server->OnDisconnect(this);
+}
diff --git a/Source/cmConnection.h b/Source/cmConnection.h
new file mode 100644
index 0000000..d477769
--- /dev/null
+++ b/Source/cmConnection.h
@@ -0,0 +1,104 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cm_uv.h"
+#include <deque>
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmServerBase;
+
+/***
+ * Given a sequence of bytes with any kind of buffering, instances of this
+ * class arrange logical chunks according to whatever the use case is for
+ * the connection.
+ */
+class cmConnectionBufferStrategy
+{
+public:
+ virtual ~cmConnectionBufferStrategy();
+
+ /***
+ * Called whenever with an active raw buffer. If a logical chunk
+ * becomes available, that chunk is returned and that portion is
+ * removed from the rawBuffer
+ *
+ * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is
+ * free to manipulate this buffer anyway it needs to.
+ *
+ * @return Next chunk from the stream. Returns the empty string if a chunk
+ * isn't ready yet. Users of this interface should repeatedly call this
+ * function until an empty string is returned since its entirely possible
+ * multiple chunks come in a single raw buffer.
+ */
+ virtual std::string BufferMessage(std::string& rawBuffer) = 0;
+
+ /***
+ * Resets the internal state of the buffering
+ */
+ virtual void clear();
+
+ // TODO: There should be a callback / flag set for errors
+};
+
+/***
+ * Abstraction of a connection; ties in event callbacks from libuv and notifies
+ * the server when appropriate
+ */
+class cmConnection
+{
+public:
+ virtual ~cmConnection();
+
+ /***
+ * @param bufferStrategy If no strategy is given, it will process the raw
+ * chunks as they come in. The connection
+ * owns the pointer given.
+ */
+ cmConnection(cmConnectionBufferStrategy* bufferStrategy = 0);
+
+ virtual void Connect(uv_stream_t* server);
+
+ virtual void ReadData(const std::string& data);
+
+ virtual bool OnServeStart(std::string* errString);
+
+ virtual bool OnServerShuttingDown();
+
+ virtual bool IsOpen() const;
+
+ virtual void WriteData(const std::string& data);
+
+ virtual void QueueRequest(const std::string& request);
+
+ virtual void ProcessNextRequest();
+
+ virtual void SetServer(cmServerBase* s);
+
+ virtual void OnDisconnect(int errorCode);
+ uv_stream_t* ReadStream = nullptr;
+ cmServerBase* Server = 0;
+ uv_stream_t* WriteStream = nullptr;
+
+ static void on_close(uv_handle_t* handle);
+ static void on_close_delete(uv_handle_t* handle);
+
+protected:
+ std::deque<std::string> Queue;
+
+ std::string RawReadBuffer;
+
+ std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy;
+
+ static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+
+ static void on_write(uv_write_t* req, int status);
+
+ static void on_new_connection(uv_stream_t* stream, int status);
+
+ static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
+ uv_buf_t* buf);
+};
diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx
new file mode 100644
index 0000000..7796574
--- /dev/null
+++ b/Source/cmPipeConnection.cxx
@@ -0,0 +1,81 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmPipeConnection.h"
+#include "cmServer.h"
+#include "cmServerConnection.h"
+
+cmPipeConnection::cmPipeConnection(const std::string& name,
+ cmConnectionBufferStrategy* bufferStrategy)
+ : cmConnection(bufferStrategy)
+ , PipeName(name)
+{
+}
+
+void cmPipeConnection::Connect(uv_stream_t* server)
+{
+ if (this->ClientPipe) {
+ // Accept and close all pipes but the first:
+ uv_pipe_t* rejectPipe = new uv_pipe_t();
+
+ uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0);
+ uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe));
+ uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), &on_close_delete);
+ return;
+ }
+
+ this->ClientPipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0);
+ this->ClientPipe->data = static_cast<cmConnection*>(this);
+
+ auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
+ if (uv_accept(server, client) != 0) {
+ uv_close(reinterpret_cast<uv_handle_t*>(client), &on_close_delete);
+ this->ClientPipe = 0;
+ return;
+ }
+ this->ReadStream = client;
+ this->WriteStream = client;
+
+ uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
+ Server->OnConnected(this);
+}
+
+bool cmPipeConnection::OnServeStart(std::string* errorMessage)
+{
+ this->ServerPipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0);
+ this->ServerPipe->data = static_cast<cmConnection*>(this);
+
+ int r;
+ if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
+ *errorMessage = std::string("Internal Error with ") + this->PipeName +
+ ": " + uv_err_name(r);
+ return false;
+ }
+ auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe);
+ if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
+ *errorMessage = std::string("Internal Error listening on ") +
+ this->PipeName + ": " + uv_err_name(r);
+ return false;
+ }
+
+ return cmConnection::OnServeStart(errorMessage);
+}
+
+bool cmPipeConnection::OnServerShuttingDown()
+{
+ if (this->ClientPipe) {
+ uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe),
+ &on_close_delete);
+ this->WriteStream->data = nullptr;
+ }
+ uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_close_delete);
+
+ this->ClientPipe = nullptr;
+ this->ServerPipe = nullptr;
+ this->WriteStream = nullptr;
+ this->ReadStream = nullptr;
+
+ return cmConnection::OnServerShuttingDown();
+}
diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h
new file mode 100644
index 0000000..f0a3aca
--- /dev/null
+++ b/Source/cmPipeConnection.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cmConnection.h"
+#include "cm_uv.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmPipeConnection : public cmConnection
+{
+public:
+ cmPipeConnection(const std::string& name,
+ cmConnectionBufferStrategy* bufferStrategy = 0);
+
+ bool OnServeStart(std::string* pString) override;
+
+ bool OnServerShuttingDown() override;
+
+ void Connect(uv_stream_t* server) override;
+
+private:
+ const std::string PipeName;
+ uv_pipe_t* ServerPipe = 0;
+ uv_pipe_t* ClientPipe = 0;
+};
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 5a71dc0..831a4cd 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -1,7 +1,10 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmServer.h"
+#include <iomanip>
+#include <sstream>
+#include "cmFileMonitor.h"
#include "cmServerConnection.h"
#include "cmServerDictionary.h"
#include "cmServerProtocol.h"
@@ -10,14 +13,35 @@
#include "cmake.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
+
#include "cm_jsoncpp_reader.h"
#include "cm_jsoncpp_value.h"
+
#endif
#include <algorithm>
#include <fstream>
#include <iostream>
-#include <memory>
+
+template <typename T>
+static void onLoop(T* handle)
+{
+ auto serverBase = reinterpret_cast<cmServerBase*>(handle->data);
+ serverBase->ProcessOneRequestPerConnection();
+}
+
+void on_signal(uv_signal_t* signal, int signum)
+{
+ auto conn = reinterpret_cast<cmServerBase*>(signal->data);
+ conn->OnSignal(signum);
+}
+
+static void on_walk_to_shutdown(uv_handle_t* handle, void* arg)
+{
+ (void)arg;
+ if (!uv_is_closing(handle))
+ uv_close(handle, &cmConnection::on_close);
+}
class cmServer::DebugInfo
{
@@ -33,11 +57,10 @@ public:
uint64_t StartTime;
};
-cmServer::cmServer(cmServerConnection* conn, bool supportExperimental)
- : Connection(conn)
+cmServer::cmServer(cmConnection* conn, bool supportExperimental)
+ : cmServerBase(conn)
, SupportExperimental(supportExperimental)
{
- this->Connection->SetServer(this);
// Register supported protocols:
this->RegisterProtocol(new cmServerProtocol1_0);
}
@@ -51,23 +74,15 @@ cmServer::~cmServer()
for (cmServerProtocol* p : this->SupportedProtocols) {
delete p;
}
-
- delete this->Connection;
}
-void cmServer::PopOne()
+void cmServer::ProcessRequest(cmConnection* connection,
+ const std::string& input)
{
- if (this->Queue.empty()) {
- return;
- }
-
Json::Reader reader;
Json::Value value;
- const std::string input = this->Queue.front();
- this->Queue.erase(this->Queue.begin());
-
if (!reader.parse(input, value)) {
- this->WriteParseError("Failed to parse JSON input.");
+ this->WriteParseError(connection, "Failed to parse JSON input.");
return;
}
@@ -85,7 +100,7 @@ void cmServer::PopOne()
if (request.Type == "") {
cmServerResponse response(request);
response.SetError("No type given in request.");
- this->WriteResponse(response, nullptr);
+ this->WriteResponse(connection, response, nullptr);
return;
}
@@ -94,9 +109,11 @@ void cmServer::PopOne()
if (this->Protocol) {
this->Protocol->CMakeInstance()->SetProgressCallback(
reportProgress, const_cast<cmServerRequest*>(&request));
- this->WriteResponse(this->Protocol->Process(request), debug.get());
+ this->WriteResponse(connection, this->Protocol->Process(request),
+ debug.get());
} else {
- this->WriteResponse(this->SetProtocolVersion(request), debug.get());
+ this->WriteResponse(connection, this->SetProtocolVersion(request),
+ debug.get());
}
}
@@ -118,7 +135,7 @@ void cmServer::RegisterProtocol(cmServerProtocol* protocol)
}
}
-void cmServer::PrintHello() const
+void cmServer::PrintHello(cmConnection* connection) const
{
Json::Value hello = Json::objectValue;
hello[kTYPE_KEY] = "hello";
@@ -137,13 +154,7 @@ void cmServer::PrintHello() const
protocolVersions.append(tmp);
}
- this->WriteJsonObject(hello, nullptr);
-}
-
-void cmServer::QueueRequest(const std::string& request)
-{
- this->Queue.push_back(request);
- this->PopOne();
+ this->WriteJsonObject(connection, hello, nullptr);
}
void cmServer::reportProgress(const char* msg, float progress, void* data)
@@ -235,17 +246,26 @@ bool cmServer::Serve(std::string* errorMessage)
}
assert(!this->Protocol);
- return Connection->ProcessEvents(errorMessage);
+ return cmServerBase::Serve(errorMessage);
}
cmFileMonitor* cmServer::FileMonitor() const
{
- return Connection->FileMonitor();
+ return fileMonitor.get();
}
void cmServer::WriteJsonObject(const Json::Value& jsonValue,
const DebugInfo* debug) const
{
+ for (auto& connection : this->Connections) {
+ WriteJsonObject(connection.get(), jsonValue, debug);
+ }
+}
+
+void cmServer::WriteJsonObject(cmConnection* connection,
+ const Json::Value& jsonValue,
+ const DebugInfo* debug) const
+{
Json::FastWriter writer;
auto beforeJson = uv_hrtime();
@@ -277,7 +297,7 @@ void cmServer::WriteJsonObject(const Json::Value& jsonValue,
}
}
- Connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") +
+ connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") +
result + kEND_MAGIC + std::string("\n"));
}
@@ -339,7 +359,8 @@ void cmServer::WriteMessage(const cmServerRequest& request,
WriteJsonObject(obj, nullptr);
}
-void cmServer::WriteParseError(const std::string& message) const
+void cmServer::WriteParseError(cmConnection* connection,
+ const std::string& message) const
{
Json::Value obj = Json::objectValue;
obj[kTYPE_KEY] = kERROR_TYPE;
@@ -347,7 +368,7 @@ void cmServer::WriteParseError(const std::string& message) const
obj[kREPLY_TO_KEY] = "";
obj[kCOOKIE_KEY] = "";
- this->WriteJsonObject(obj, nullptr);
+ this->WriteJsonObject(connection, obj, nullptr);
}
void cmServer::WriteSignal(const std::string& name,
@@ -363,7 +384,8 @@ void cmServer::WriteSignal(const std::string& name,
WriteJsonObject(obj, nullptr);
}
-void cmServer::WriteResponse(const cmServerResponse& response,
+void cmServer::WriteResponse(cmConnection* connection,
+ const cmServerResponse& response,
const DebugInfo* debug) const
{
assert(response.IsComplete());
@@ -376,5 +398,176 @@ void cmServer::WriteResponse(const cmServerResponse& response,
obj[kERROR_MESSAGE_KEY] = response.ErrorMessage();
}
- this->WriteJsonObject(obj, debug);
+ this->WriteJsonObject(connection, obj, debug);
+}
+
+void cmServer::OnConnected(cmConnection* connection)
+{
+ PrintHello(connection);
+}
+
+void cmServer::OnServeStart()
+{
+ cmServerBase::OnServeStart();
+ fileMonitor = std::make_shared<cmFileMonitor>(GetLoop());
+}
+
+void cmServer::StartShutDown()
+{
+ cmServerBase::StartShutDown();
+ if (fileMonitor) {
+ fileMonitor->StopMonitoring();
+ fileMonitor.reset();
+ }
+}
+
+bool cmServerBase::StartServeThread()
+{
+ ServeThread = std::thread([&] {
+ std::string error;
+ Serve(&error);
+ });
+ return true;
+}
+
+bool cmServerBase::Serve(std::string* errorMessage)
+{
+ errorMessage->clear();
+
+ uv_signal_init(&Loop, &this->SIGINTHandler);
+ uv_signal_init(&Loop, &this->SIGHUPHandler);
+
+ this->SIGINTHandler.data = this;
+ this->SIGHUPHandler.data = this;
+
+ uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT);
+ uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP);
+
+ uv_check_init(&Loop, &cbHandle);
+ cbHandle.data = this;
+ uv_check_start(&cbHandle, &onLoop);
+
+ uv_prepare_init(&Loop, &cbPrepareHandle);
+ cbPrepareHandle.data = this;
+ uv_prepare_start(&cbPrepareHandle, &onLoop);
+
+ OnServeStart();
+
+ for (auto& connection : Connections) {
+ if (!connection->OnServeStart(errorMessage))
+ return false;
+ }
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ *errorMessage = "Internal Error: Event loop stopped in unclean state.";
+ StartShutDown();
+ return false;
+ }
+
+ return true;
+}
+
+void cmServerBase::OnConnected(cmConnection*)
+{
+}
+
+void cmServerBase::OnDisconnect()
+{
+}
+
+void cmServerBase::OnServeStart()
+{
+ uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT);
+ uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP);
+ uv_prepare_start(&cbPrepareHandle, &onLoop);
+ uv_check_start(&cbHandle, &onLoop);
+}
+
+void cmServerBase::StartShutDown()
+{
+ if (!uv_is_closing((const uv_handle_t*)&this->SIGINTHandler))
+ uv_signal_stop(&this->SIGINTHandler);
+ if (!uv_is_closing((const uv_handle_t*)&this->SIGHUPHandler))
+ uv_signal_stop(&this->SIGHUPHandler);
+ uv_prepare_stop(&cbPrepareHandle);
+ uv_check_stop(&cbHandle);
+
+ for (auto& connection : Connections)
+ connection->OnServerShuttingDown();
+
+ uv_stop(&Loop);
+ if (!uv_is_closing((const uv_handle_t*)&WakeupLoop))
+ uv_async_send(&WakeupLoop);
+ uv_walk(&Loop, on_walk_to_shutdown, NULL);
+}
+
+bool cmServerBase::OnSignal(int signum)
+{
+ (void)signum;
+ StartShutDown();
+ return true;
+}
+
+cmServerBase::cmServerBase(cmConnection* connection)
+{
+ uv_loop_init(&Loop);
+ uv_async_init(&Loop, &WakeupLoop, 0);
+
+ uv_signal_init(&Loop, &this->SIGINTHandler);
+ uv_signal_init(&Loop, &this->SIGHUPHandler);
+
+ this->SIGINTHandler.data = this;
+ this->SIGHUPHandler.data = this;
+
+ uv_check_init(&Loop, &cbHandle);
+ cbHandle.data = this;
+
+ uv_prepare_init(&Loop, &cbPrepareHandle);
+ cbPrepareHandle.data = this;
+
+ AddNewConnection(connection);
+}
+
+cmServerBase::~cmServerBase()
+{
+ Connections.clear();
+
+ StartShutDown();
+
+ if (ServeThread.joinable())
+ ServeThread.join();
+}
+
+void cmServerBase::AddNewConnection(cmConnection* ownedConnection)
+{
+ Connections.emplace_back(ownedConnection);
+ ownedConnection->SetServer(this);
+}
+
+void cmServerBase::ProcessOneRequestPerConnection()
+{
+ for (auto& connection : Connections)
+ connection->ProcessNextRequest();
+}
+
+uv_loop_t* cmServerBase::GetLoop()
+{
+ return &Loop;
+}
+
+void cmServerBase::OnDisconnect(cmConnection* pConnection)
+{
+ auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) {
+ return m.get() == pConnection;
+ };
+ Connections.erase(
+ std::remove_if(Connections.begin(), Connections.end(), pred),
+ Connections.end());
+ if (Connections.empty())
+ StartShutDown();
+}
+
+void cmServerBase::NotifyDataQueued()
+{
+ uv_async_send(&WakeupLoop);
}
diff --git a/Source/cmServer.h b/Source/cmServer.h
index 7f29e32..d2aebb6 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -6,28 +6,110 @@
#include "cmState.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmConnection.h"
+#include "cmServerConnection.h"
+#endif
+
#include "cm_jsoncpp_value.h"
#include "cm_uv.h"
-#endif
-#include <string>
-#include <vector>
+#include <thread>
class cmFileMonitor;
-class cmServerConnection;
+class cmConnection;
class cmServerProtocol;
class cmServerRequest;
class cmServerResponse;
-class cmServer
+/***
+ * This essentially hold and manages a libuv event queue and responds to
+ * messages
+ * on any of its connections.
+ */
+class cmServerBase
+{
+public:
+ cmServerBase(cmConnection* connection);
+ virtual ~cmServerBase();
+
+ virtual void AddNewConnection(cmConnection* ownedConnection);
+
+ /***
+ * Called to force the server to service one request per connection
+ * We don't do just the first one we see otherwise we could starve
+ * connections based on their place in the connection list.
+ */
+ virtual void ProcessOneRequestPerConnection();
+
+ /***
+ * The main override responsible for tailoring behavior towards
+ * whatever the given server is supposed to do
+ *
+ * This should almost always be called by the given connections
+ * directly.
+ *
+ * @param connection The connectiont the request was received on
+ * @param request The actual request
+ */
+ virtual void ProcessRequest(cmConnection* connection,
+ const std::string& request) = 0;
+ virtual void OnConnected(cmConnection* connection);
+ virtual void OnDisconnect();
+
+ /***
+ * Start a dedicated thread. If this is used to start the server, it will
+ * join on the
+ * servers dtor.
+ */
+ virtual bool StartServeThread();
+ virtual bool Serve(std::string* errorMessage);
+
+ // Notification from any connection that it received more data to
+ // process. It can safely be called spuriously.
+ virtual void NotifyDataQueued();
+
+ virtual void OnServeStart();
+ virtual void StartShutDown();
+
+ virtual bool OnSignal(int signum);
+ uv_loop_t* GetLoop();
+
+ void OnDisconnect(cmConnection* pConnection);
+
+protected:
+ std::vector<std::unique_ptr<cmConnection> > Connections;
+
+ std::thread ServeThread;
+
+ uv_loop_t Loop;
+
+ uv_signal_t SIGINTHandler;
+ uv_signal_t SIGHUPHandler;
+
+ /** Note -- We run the same callback in prepare and check to properly handle
+ deferred call
+ */
+
+ // TODO: Currently the async wakes up the loop and the check / prepare
+ // callbacks
+ // actually do the processing if there is anything to process. This is likely
+ // unneeded, we could probably just use the async CB for that.
+
+ // Semaphore used to wake up the thread to do some action
+ uv_async_t WakeupLoop;
+ uv_check_t cbHandle;
+ uv_prepare_t cbPrepareHandle;
+};
+
+class cmServer : public cmServerBase
{
public:
class DebugInfo;
- cmServer(cmServerConnection* conn, bool supportExperimental);
+ cmServer(cmConnection* conn, bool supportExperimental);
~cmServer();
- bool Serve(std::string* errorMessage);
+ virtual bool Serve(std::string* errorMessage) override;
cmFileMonitor* FileMonitor() const;
@@ -35,9 +117,20 @@ private:
void RegisterProtocol(cmServerProtocol* protocol);
// Callbacks from cmServerConnection:
- void PopOne();
- void QueueRequest(const std::string& request);
+ virtual void ProcessRequest(cmConnection* connection,
+ const std::string& request) override;
+ std::shared_ptr<cmFileMonitor> fileMonitor;
+
+public:
+ void OnServeStart() override;
+
+ void StartShutDown() override;
+
+public:
+ void OnConnected(cmConnection* connection) override;
+
+private:
static void reportProgress(const char* msg, float progress, void* data);
static void reportMessage(const char* msg, const char* title, bool& cancel,
void* data);
@@ -45,30 +138,33 @@ private:
// Handle requests:
cmServerResponse SetProtocolVersion(const cmServerRequest& request);
- void PrintHello() const;
+ void PrintHello(cmConnection* connection) const;
// Write responses:
void WriteProgress(const cmServerRequest& request, int min, int current,
int max, const std::string& message) const;
void WriteMessage(const cmServerRequest& request, const std::string& message,
const std::string& title) const;
- void WriteResponse(const cmServerResponse& response,
+ void WriteResponse(cmConnection* connection,
+ const cmServerResponse& response,
const DebugInfo* debug) const;
- void WriteParseError(const std::string& message) const;
+ void WriteParseError(cmConnection* connection,
+ const std::string& message) const;
void WriteSignal(const std::string& name, const Json::Value& obj) const;
void WriteJsonObject(Json::Value const& jsonValue,
const DebugInfo* debug) const;
+ void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue,
+ const DebugInfo* debug) const;
+
static cmServerProtocol* FindMatchingProtocol(
const std::vector<cmServerProtocol*>& protocols, int major, int minor);
- cmServerConnection* Connection = nullptr;
const bool SupportExperimental;
cmServerProtocol* Protocol = nullptr;
std::vector<cmServerProtocol*> SupportedProtocols;
- std::vector<std::string> Queue;
std::string DataBuffer;
std::string JsonData;
@@ -88,7 +184,6 @@ private:
mutable bool Writing = false;
- friend class cmServerConnection;
friend class cmServerProtocol;
friend class cmServerRequest;
};
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 008052b..cdd1584 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -6,373 +6,109 @@
#include "cmFileMonitor.h"
#include "cmServer.h"
+#include <fstream>
-#include <assert.h>
-#include <string.h>
-
-namespace {
-
-struct write_req_t
+cmStdIoConnection::cmStdIoConnection(
+ cmConnectionBufferStrategy* bufferStrategy)
+ : cmConnection(bufferStrategy)
{
- uv_write_t req;
- uv_buf_t buf;
-};
-
-void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
-{
- (void)(handle);
- char* rawBuffer = new char[suggested_size];
- *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
}
-void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
+void cmStdIoConnection::SetServer(cmServerBase* s)
{
- auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
- if (nread >= 0) {
- conn->ReadData(std::string(buf->base, buf->base + nread));
+ cmConnection::SetServer(s);
+
+ if (uv_guess_handle(1) == UV_TTY) {
+ usesTty = true;
+ uv_tty_init(this->Server->GetLoop(), &this->Input.tty, 0, 1);
+ uv_tty_set_mode(&this->Input.tty, UV_TTY_MODE_NORMAL);
+ Input.tty.data = static_cast<cmConnection*>(this);
+ this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.tty);
+
+ uv_tty_init(this->Server->GetLoop(), &this->Output.tty, 1, 0);
+ uv_tty_set_mode(&this->Output.tty, UV_TTY_MODE_NORMAL);
+ Output.tty.data = static_cast<cmConnection*>(this);
+ this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.tty);
} else {
- conn->TriggerShutdown();
+ usesTty = false;
+ uv_pipe_init(this->Server->GetLoop(), &this->Input.pipe, 0);
+ uv_pipe_open(&this->Input.pipe, 0);
+ Input.pipe.data = static_cast<cmConnection*>(this);
+ this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.pipe);
+
+ uv_pipe_init(this->Server->GetLoop(), &this->Output.pipe, 0);
+ uv_pipe_open(&this->Output.pipe, 1);
+ Output.pipe.data = static_cast<cmConnection*>(this);
+ this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.pipe);
}
-
- delete[](buf->base);
-}
-
-void on_write(uv_write_t* req, int status)
-{
- (void)(status);
- auto conn = reinterpret_cast<cmServerConnection*>(req->data);
-
- // Free req and buffer
- write_req_t* wr = reinterpret_cast<write_req_t*>(req);
- delete[](wr->buf.base);
- delete wr;
-
- conn->ProcessNextRequest();
-}
-
-void on_new_connection(uv_stream_t* stream, int status)
-{
- (void)(status);
- auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
- conn->Connect(stream);
}
-void on_signal(uv_signal_t* signal, int signum)
+bool cmStdIoConnection::OnServeStart(std::string* pString)
{
- auto conn = reinterpret_cast<cmServerConnection*>(signal->data);
- (void)(signum);
- conn->TriggerShutdown();
-}
-
-void on_signal_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_signal_t*>(handle);
-}
-
-void on_pipe_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_pipe_t*>(handle);
-}
-
-void on_tty_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_tty_t*>(handle);
+ uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
+ Server->OnConnected(this);
+ return cmConnection::OnServeStart(pString);
}
-} // namespace
-
-class LoopGuard
+bool cmStdIoConnection::OnServerShuttingDown()
{
-public:
- LoopGuard(cmServerConnection* connection)
- : Connection(connection)
- {
- this->Connection->mLoop = uv_default_loop();
- if (!this->Connection->mLoop) {
- return;
- }
- this->Connection->mFileMonitor =
- new cmFileMonitor(this->Connection->mLoop);
- }
-
- ~LoopGuard()
- {
- if (!this->Connection->mLoop) {
- return;
- }
-
- if (this->Connection->mFileMonitor) {
- delete this->Connection->mFileMonitor;
- }
- uv_loop_close(this->Connection->mLoop);
- this->Connection->mLoop = nullptr;
+ if (usesTty) {
+ uv_read_stop(reinterpret_cast<uv_stream_t*>(&this->Input.tty));
+ uv_close(reinterpret_cast<uv_handle_t*>(&this->Input.tty), &on_close);
+ uv_close(reinterpret_cast<uv_handle_t*>(&this->Output.tty), &on_close);
+ } else {
+ uv_close(reinterpret_cast<uv_handle_t*>(&this->Input.pipe), &on_close);
+ uv_close(reinterpret_cast<uv_handle_t*>(&this->Output.pipe), &on_close);
}
+ this->ReadStream = nullptr;
+ this->WriteStream = nullptr;
+ return true;
+}
-private:
- cmServerConnection* Connection;
-};
-
-cmServerConnection::cmServerConnection()
+cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
+ : cmPipeConnection(name, new cmServerBufferStrategy)
{
}
-cmServerConnection::~cmServerConnection()
+cmServerStdIoConnection::cmServerStdIoConnection()
+ : cmStdIoConnection(new cmServerBufferStrategy)
{
}
-void cmServerConnection::SetServer(cmServer* s)
+cmConnectionBufferStrategy::~cmConnectionBufferStrategy()
{
- this->Server = s;
}
-bool cmServerConnection::ProcessEvents(std::string* errorMessage)
+void cmConnectionBufferStrategy::clear()
{
- assert(this->Server);
- errorMessage->clear();
-
- this->RawReadBuffer.clear();
- this->RequestBuffer.clear();
-
- LoopGuard guard(this);
- (void)(guard);
- if (!this->mLoop) {
- *errorMessage = "Internal Error: Failed to create event loop.";
- return false;
- }
-
- this->SIGINTHandler = new uv_signal_t;
- uv_signal_init(this->mLoop, this->SIGINTHandler);
- this->SIGINTHandler->data = static_cast<void*>(this);
- uv_signal_start(this->SIGINTHandler, &on_signal, SIGINT);
-
- this->SIGHUPHandler = new uv_signal_t;
- uv_signal_init(this->mLoop, this->SIGHUPHandler);
- this->SIGHUPHandler->data = static_cast<void*>(this);
- uv_signal_start(this->SIGHUPHandler, &on_signal, SIGHUP);
-
- if (!DoSetup(errorMessage)) {
- return false;
- }
-
- if (uv_run(this->mLoop, UV_RUN_DEFAULT) != 0) {
- *errorMessage = "Internal Error: Event loop stopped in unclean state.";
- return false;
- }
-
- // These need to be cleaned up by now:
- assert(!this->ReadStream);
- assert(!this->WriteStream);
-
- this->RawReadBuffer.clear();
- this->RequestBuffer.clear();
-
- return true;
}
-void cmServerConnection::ReadData(const std::string& data)
+std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer)
{
- this->RawReadBuffer += data;
-
for (;;) {
- auto needle = this->RawReadBuffer.find('\n');
+ auto needle = RawReadBuffer.find('\n');
if (needle == std::string::npos) {
- return;
+ return "";
}
- std::string line = this->RawReadBuffer.substr(0, needle);
+ std::string line = RawReadBuffer.substr(0, needle);
const auto ls = line.size();
if (ls > 1 && line.at(ls - 1) == '\r') {
line.erase(ls - 1, 1);
}
- this->RawReadBuffer.erase(this->RawReadBuffer.begin(),
- this->RawReadBuffer.begin() +
- static_cast<long>(needle) + 1);
+ RawReadBuffer.erase(RawReadBuffer.begin(),
+ RawReadBuffer.begin() + static_cast<long>(needle) + 1);
if (line == kSTART_MAGIC) {
- this->RequestBuffer.clear();
+ RequestBuffer.clear();
continue;
}
if (line == kEND_MAGIC) {
- this->Server->QueueRequest(this->RequestBuffer);
- this->RequestBuffer.clear();
+ std::string rtn;
+ rtn.swap(this->RequestBuffer);
+ return rtn;
} else {
this->RequestBuffer += line;
this->RequestBuffer += "\n";
}
}
}
-
-void cmServerConnection::TriggerShutdown()
-{
- this->FileMonitor()->StopMonitoring();
-
- uv_signal_stop(this->SIGINTHandler);
- uv_signal_stop(this->SIGHUPHandler);
-
- uv_close(reinterpret_cast<uv_handle_t*>(this->SIGINTHandler),
- &on_signal_close); // delete handle
- uv_close(reinterpret_cast<uv_handle_t*>(this->SIGHUPHandler),
- &on_signal_close); // delete handle
-
- this->SIGINTHandler = nullptr;
- this->SIGHUPHandler = nullptr;
-
- this->TearDown();
-}
-
-void cmServerConnection::WriteData(const std::string& data)
-{
- assert(this->WriteStream);
-
- auto ds = data.size();
-
- write_req_t* req = new write_req_t;
- req->req.data = this;
- req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
- memcpy(req->buf.base, data.c_str(), ds);
-
- uv_write(reinterpret_cast<uv_write_t*>(req),
- static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
- on_write);
-}
-
-void cmServerConnection::ProcessNextRequest()
-{
- Server->PopOne();
-}
-
-void cmServerConnection::SendGreetings()
-{
- Server->PrintHello();
-}
-
-cmServerStdIoConnection::cmServerStdIoConnection()
-{
- this->Input.tty = nullptr;
- this->Output.tty = nullptr;
-}
-
-bool cmServerStdIoConnection::DoSetup(std::string* errorMessage)
-{
- (void)(errorMessage);
-
- if (uv_guess_handle(1) == UV_TTY) {
- usesTty = true;
- this->Input.tty = new uv_tty_t;
- uv_tty_init(this->Loop(), this->Input.tty, 0, 1);
- uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL);
- Input.tty->data = this;
- this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty);
-
- this->Output.tty = new uv_tty_t;
- uv_tty_init(this->Loop(), this->Output.tty, 1, 0);
- uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL);
- Output.tty->data = this;
- this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty);
- } else {
- usesTty = false;
- this->Input.pipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->Input.pipe, 0);
- uv_pipe_open(this->Input.pipe, 0);
- Input.pipe->data = this;
- this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe);
-
- this->Output.pipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->Output.pipe, 0);
- uv_pipe_open(this->Output.pipe, 1);
- Output.pipe->data = this;
- this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe);
- }
-
- SendGreetings();
- uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
-
- return true;
-}
-
-void cmServerStdIoConnection::TearDown()
-{
- if (usesTty) {
- uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty), &on_tty_close);
- uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty), &on_tty_close);
- this->Input.tty = nullptr;
- this->Output.tty = nullptr;
- } else {
- uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe), &on_pipe_close);
- uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe),
- &on_pipe_close);
- this->Input.pipe = nullptr;
- this->Input.pipe = nullptr;
- }
- this->ReadStream = nullptr;
- this->WriteStream = nullptr;
-}
-
-cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
- : PipeName(name)
-{
-}
-
-bool cmServerPipeConnection::DoSetup(std::string* errorMessage)
-{
- this->ServerPipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->ServerPipe, 0);
- this->ServerPipe->data = this;
-
- int r;
- if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
- *errorMessage = std::string("Internal Error with ") + this->PipeName +
- ": " + uv_err_name(r);
- return false;
- }
- auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe);
- if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
- *errorMessage = std::string("Internal Error listening on ") +
- this->PipeName + ": " + uv_err_name(r);
- return false;
- }
-
- return true;
-}
-
-void cmServerPipeConnection::TearDown()
-{
- if (this->ClientPipe) {
- uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), &on_pipe_close);
- this->WriteStream->data = nullptr;
- }
- uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_pipe_close);
-
- this->ClientPipe = nullptr;
- this->ServerPipe = nullptr;
- this->WriteStream = nullptr;
- this->ReadStream = nullptr;
-}
-
-void cmServerPipeConnection::Connect(uv_stream_t* server)
-{
- if (this->ClientPipe) {
- // Accept and close all pipes but the first:
- uv_pipe_t* rejectPipe = new uv_pipe_t;
-
- uv_pipe_init(this->Loop(), rejectPipe, 0);
- auto rejecter = reinterpret_cast<uv_stream_t*>(rejectPipe);
- uv_accept(server, rejecter);
- uv_close(reinterpret_cast<uv_handle_t*>(rejecter), &on_pipe_close);
- return;
- }
-
- this->ClientPipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->ClientPipe, 0);
- this->ClientPipe->data = this;
- auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
- if (uv_accept(server, client) != 0) {
- uv_close(reinterpret_cast<uv_handle_t*>(client), nullptr);
- return;
- }
- this->ReadStream = client;
- this->WriteStream = client;
-
- uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
-
- this->SendGreetings();
-}
diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h
index 3efe28d..f7f4c17 100644
--- a/Source/cmServerConnection.h
+++ b/Source/cmServerConnection.h
@@ -5,71 +5,52 @@
#include <string>
#include <vector>
-#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmConnection.h"
+#include "cmPipeConnection.h"
#include "cm_uv.h"
-#endif
class cmServer;
+class cmServerBase;
class cmFileMonitor;
class LoopGuard;
-class cmServerConnection
+/***
+ * This connection buffer strategy accepts messages in the form of
+ * [== "CMake Server" ==[
+{
+ ... some JSON message ...
+}
+]== "CMake Server" ==]
+ * and only passes on the core json; it discards the envelope.
+ */
+class cmServerBufferStrategy : public cmConnectionBufferStrategy
{
public:
- cmServerConnection();
- virtual ~cmServerConnection();
-
- void SetServer(cmServer* s);
-
- bool ProcessEvents(std::string* errorMessage);
-
- void ReadData(const std::string& data);
- void TriggerShutdown();
- void WriteData(const std::string& data);
- void ProcessNextRequest();
-
- virtual void Connect(uv_stream_t* server) { (void)(server); }
-
- cmFileMonitor* FileMonitor() const { return this->mFileMonitor; }
-
-protected:
- virtual bool DoSetup(std::string* errorMessage) = 0;
- virtual void TearDown() = 0;
-
- void SendGreetings();
-
- uv_loop_t* Loop() const { return mLoop; }
-
-protected:
- std::string RawReadBuffer;
- std::string RequestBuffer;
-
- uv_stream_t* ReadStream = nullptr;
- uv_stream_t* WriteStream = nullptr;
+ std::string BufferMessage(std::string& rawBuffer) override;
private:
- uv_loop_t* mLoop = nullptr;
- cmFileMonitor* mFileMonitor = nullptr;
- cmServer* Server = nullptr;
- uv_signal_t* SIGINTHandler = nullptr;
- uv_signal_t* SIGHUPHandler = nullptr;
-
- friend class LoopGuard;
+ std::string RequestBuffer;
};
-class cmServerStdIoConnection : public cmServerConnection
+/***
+ * Generic connection over std io interfaces -- tty
+ */
+class cmStdIoConnection : public cmConnection
{
public:
- cmServerStdIoConnection();
- bool DoSetup(std::string* errorMessage) override;
+ cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy);
+
+ void SetServer(cmServerBase* s) override;
+
+ bool OnServerShuttingDown() override;
- void TearDown() override;
+ bool OnServeStart(std::string* pString) override;
private:
typedef union
{
- uv_tty_t* tty;
- uv_pipe_t* pipe;
+ uv_tty_t tty;
+ uv_pipe_t pipe;
} InOutUnion;
bool usesTty = false;
@@ -78,18 +59,18 @@ private:
InOutUnion Output;
};
-class cmServerPipeConnection : public cmServerConnection
+/***
+ * These specific connections use the cmake server
+ * buffering strategy.
+ */
+class cmServerStdIoConnection : public cmStdIoConnection
{
public:
- cmServerPipeConnection(const std::string& name);
- bool DoSetup(std::string* errorMessage) override;
-
- void TearDown() override;
-
- void Connect(uv_stream_t* server) override;
+ cmServerStdIoConnection();
+};
-private:
- const std::string PipeName;
- uv_pipe_t* ServerPipe = nullptr;
- uv_pipe_t* ClientPipe = nullptr;
+class cmServerPipeConnection : public cmPipeConnection
+{
+public:
+ cmServerPipeConnection(const std::string& name);
};
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 823b38f..b0a0fd9 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1006,7 +1006,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
}
#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE
- cmServerConnection* conn;
+ cmConnection* conn;
if (isDebug) {
conn = new cmServerStdIoConnection;
} else {
-----------------------------------------------------------------------
Summary of changes:
Packaging/QtSDK/ToolsCMakeXX.cmake | 2 +-
Packaging/QtSDK/qt.tools.cmake.xx.qs.in | 30 ++-
Source/CMakeLists.txt | 2 +
Source/cmConnection.cxx | 158 +++++++++++++
Source/cmConnection.h | 114 +++++++++
Source/cmPipeConnection.cxx | 80 +++++++
Source/cmPipeConnection.h | 28 +++
Source/cmServer.cxx | 266 ++++++++++++++++++---
Source/cmServer.h | 125 ++++++++--
Source/cmServerConnection.cxx | 384 +++++--------------------------
Source/cmServerConnection.h | 95 +++-----
Source/cmServerProtocol.cxx | 12 +-
Source/cmServerProtocol.h | 8 +-
Source/cmcmd.cxx | 2 +-
14 files changed, 849 insertions(+), 457 deletions(-)
create mode 100644 Source/cmConnection.cxx
create mode 100644 Source/cmConnection.h
create mode 100644 Source/cmPipeConnection.cxx
create mode 100644 Source/cmPipeConnection.h
hooks/post-receive
--
CMake
More information about the Cmake-commits
mailing list