aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/httpsys.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenhttp/httpsys.cpp')
-rw-r--r--src/zenhttp/httpsys.cpp82
1 files changed, 68 insertions, 14 deletions
diff --git a/src/zenhttp/httpsys.cpp b/src/zenhttp/httpsys.cpp
index 993b065c0..c1b4717cb 100644
--- a/src/zenhttp/httpsys.cpp
+++ b/src/zenhttp/httpsys.cpp
@@ -32,7 +32,10 @@ namespace zen {
/**
* @brief Windows implementation of HTTP server based on http.sys
*
- * This requires elevation to function
+ * This requires elevation to function by default but system configuration
+ * can soften this requirement.
+ *
+ * See README.md for details.
*/
class HttpSysServer : public HttpServer
{
@@ -76,7 +79,8 @@ private:
bool m_IsRequestLoggingEnabled = false;
bool m_IsAsyncResponseEnabled = true;
- WinIoThreadPool m_ThreadPool;
+ std::unique_ptr<WinIoThreadPool> m_IoThreadPool;
+
RwLock m_AsyncWorkPoolInitLock;
WorkerThreadPool* m_AsyncWorkPool = nullptr;
@@ -89,7 +93,7 @@ private:
int32_t m_MinPendingRequests = 16;
int32_t m_MaxPendingRequests = 128;
Event m_ShutdownEvent;
- const HttpSysConfig m_InitialConfig;
+ HttpSysConfig m_InitialConfig;
};
} // namespace zen
@@ -889,14 +893,45 @@ HttpAsyncWorkRequest::AsyncWorkItem::Execute()
\/ \/ \/
*/
-HttpSysServer::HttpSysServer(const HttpSysConfig& Config)
+HttpSysServer::HttpSysServer(const HttpSysConfig& InConfig)
: m_Log(logging::Get("http"))
, m_RequestLog(logging::Get("http_requests"))
-, m_IsRequestLoggingEnabled(Config.IsRequestLoggingEnabled)
-, m_IsAsyncResponseEnabled(Config.IsAsyncResponseEnabled)
-, m_ThreadPool(Config.ThreadCount != 0 ? Config.ThreadCount : std::thread::hardware_concurrency())
-, m_InitialConfig(Config)
+, m_IsRequestLoggingEnabled(InConfig.IsRequestLoggingEnabled)
+, m_IsAsyncResponseEnabled(InConfig.IsAsyncResponseEnabled)
+, m_InitialConfig(InConfig)
{
+ // Initialize thread pool
+
+ int MinThreadCount;
+ int MaxThreadCount;
+
+ if (m_InitialConfig.ThreadCount == 0)
+ {
+ MinThreadCount = Max(8u, std::thread::hardware_concurrency());
+ }
+ else
+ {
+ MinThreadCount = m_InitialConfig.ThreadCount;
+ }
+
+ MaxThreadCount = MinThreadCount * 2;
+
+ if (m_InitialConfig.IsDedicatedServer)
+ {
+ // In order to limit the potential impact of threads stuck
+ // in locks we allow the thread pool to be oversubscribed
+ // by a fair amount
+
+ MaxThreadCount *= 2;
+ }
+
+ m_IoThreadPool = std::make_unique<WinIoThreadPool>(MinThreadCount, MaxThreadCount);
+
+ if (m_InitialConfig.AsyncWorkThreadCount == 0)
+ {
+ m_InitialConfig.AsyncWorkThreadCount = 16;
+ }
+
ULONG Result = HttpInitialize(HTTPAPI_VERSION_2, HTTP_INITIALIZE_SERVER, nullptr);
if (Result != NO_ERROR)
@@ -907,7 +942,11 @@ HttpSysServer::HttpSysServer(const HttpSysConfig& Config)
m_IsHttpInitialized = true;
m_IsOk = true;
- ZEN_INFO("http.sys server started, using {} I/O threads and {} async worker threads", Config.ThreadCount, Config.AsyncWorkThreadCount);
+ ZEN_INFO("http.sys server started in {} mode, using {}-{} I/O threads and {} async worker threads",
+ m_InitialConfig.IsDedicatedServer ? "DEDICATED" : "NORMAL",
+ MinThreadCount,
+ MaxThreadCount,
+ m_InitialConfig.AsyncWorkThreadCount);
}
HttpSysServer::~HttpSysServer()
@@ -1070,10 +1109,27 @@ HttpSysServer::InitializeServer(int BasePort)
0);
}
+ // Tune the maximum number of pending requests in the http.sys request queue. By default
+ // the value is 1000 which is plenty for single user machines but for dedicated servers
+ // serving many users it makes sense to increase this to a higher number to help smooth
+ // out intermittent stalls like we might experience when GC is triggered
+
+ if (m_InitialConfig.IsDedicatedServer)
+ {
+ ULONG QueueLength = 50000;
+
+ Result = HttpSetRequestQueueProperty(m_RequestQueueHandle, HttpServerQueueLengthProperty, &QueueLength, sizeof QueueLength, 0, 0);
+
+ if (Result != NO_ERROR)
+ {
+ ZEN_WARN("changing request queue length to {} failed: {}", QueueLength, Result);
+ }
+ }
+
// Create I/O completion port
std::error_code ErrorCode;
- m_ThreadPool.CreateIocp(m_RequestQueueHandle, HttpSysTransaction::IoCompletionCallback, /* Context */ this, /* out */ ErrorCode);
+ m_IoThreadPool->CreateIocp(m_RequestQueueHandle, HttpSysTransaction::IoCompletionCallback, /* Context */ this, /* out */ ErrorCode);
if (ErrorCode)
{
@@ -1137,9 +1193,7 @@ HttpSysServer::WorkPool()
if (!m_AsyncWorkPool)
{
- unsigned int WorkerThreadCount = m_InitialConfig.AsyncWorkThreadCount != 0 ? m_InitialConfig.AsyncWorkThreadCount : 16;
-
- m_AsyncWorkPool = new WorkerThreadPool(WorkerThreadCount, "http_async");
+ m_AsyncWorkPool = new WorkerThreadPool(m_InitialConfig.AsyncWorkThreadCount, "http_async");
}
}
@@ -1305,7 +1359,7 @@ HttpSysTransaction::~HttpSysTransaction()
PTP_IO
HttpSysTransaction::Iocp()
{
- return m_HttpServer.m_ThreadPool.Iocp();
+ return m_HttpServer.m_IoThreadPool->Iocp();
}
HANDLE