35 m_transceiver(
std::bind(
38 std::placeholders::_1,
39 std::placeholders::_2)),
46 m_managementRecordCount(0),
47 m_badSocketMessageCount(0),
48 m_badSocketKillCount(0),
50 m_activeThreads(threads),
55 FAIL_LOG(
"You're not allowed to have multiple manager instances")
57 DIAG_LOG(
"Manager_base::Manager_base(): Initialized")
62 std::lock_guard<std::mutex> lock(m_tasksMutex);
64 m_transceiver.terminate();
70 std::lock_guard<std::mutex> lock(m_tasksMutex);
78 std::lock_guard<std::mutex> lock(m_tasksMutex);
79 DIAG_LOG(
"Starting fastcgi++ manager")
82 m_transceiver.start();
83 for(
auto& thread: m_threads)
84 if(!thread.joinable())
87 thread.swap(newThread);
93 for(
auto& thread: m_threads)
102 struct sigaction sigAction;
104 sigemptyset(&sigAction.sa_mask);
105 sigAction.sa_flags=0;
107 sigaction(SIGPIPE, &sigAction, NULL);
108 sigaction(SIGUSR1, &sigAction, NULL);
109 sigaction(SIGTERM, &sigAction, NULL);
120 DIAG_LOG(
"Received SIGUSR1. Stopping fastcgi++ manager.")
124 WARNING_LOG(
"Received SIGUSR1 but fastcgi++ manager isn't "\
132 DIAG_LOG(
"Received SIGTERM. Terminating fastcgi++ manager.")
133 instance->terminate();
136 WARNING_LOG(
"Received SIGTERM but fastcgi++ manager isn't "\
148 std::lock_guard<std::mutex> lock(m_messagesMutex);
149 message = std::move(m_messages.front().first);
150 socket = m_messages.front().second;
154 if(message.
type == 0)
177 if(std::equal(name, value,
"FCGI_MAX_CONNS"))
180 reinterpret_cast<const char*>(
192 if(std::equal(name, value,
"FCGI_MAX_REQS"))
195 reinterpret_cast<const char*>(
207 if(std::equal(name, value,
"FCGI_MPXS_CONNS"))
210 reinterpret_cast<const char*>(
244 m_transceiver.send(socket, std::move(record),
false);
251 ERROR_LOG(
"Got a non-FastCGI record destined for the manager")
256 std::unique_lock<std::shared_timed_mutex> requestsWriteLock(
259 std::unique_lock<std::mutex> tasksLock(m_tasksMutex);
260 std::shared_lock<std::shared_timed_mutex> requestsReadLock(m_requestsMutex);
262 while(!m_terminate && !(m_stop && m_requests.empty()))
264 requestsReadLock.unlock();
265 while(!m_tasks.empty())
267 auto id = m_tasks.front();
275 requestsReadLock.lock();
276 auto request = m_requests.find(
id);
277 if(request != m_requests.end())
279 std::unique_lock<std::mutex> requestLock(
280 request->second->mutex,
282 requestsReadLock.unlock();
286 auto lock = request->second->handler();
287 if(!lock || !
id.m_socket.valid())
289 #if FASTCGIPP_LOG_LEVEL > 3 290 if(!
id.m_socket.valid())
291 ++m_badSocketKillCount;
295 requestsWriteLock.lock();
296 requestLock.unlock();
297 m_requests.erase(request);
298 requestsWriteLock.unlock();
302 requestLock.unlock();
308 requestsReadLock.unlock();
313 requestsReadLock.lock();
314 if(m_terminate || (m_stop && m_requests.empty()))
316 requestsReadLock.unlock();
317 #if FASTCGIPP_LOG_LEVEL > 3 320 m_wake.wait(tasksLock);
321 #if FASTCGIPP_LOG_LEVEL > 3 322 if(!m_stop && !m_terminate)
325 m_maxActiveThreads = std::max(m_activeThreads, m_maxActiveThreads);
328 requestsReadLock.lock();
336 #if FASTCGIPP_LOG_LEVEL > 3 337 ++m_managementRecordCount;
339 std::lock_guard<std::mutex> lock(m_messagesMutex);
340 m_messages.push(std::make_pair(std::move(message),
id.m_socket));
344 #if FASTCGIPP_LOG_LEVEL > 3 345 ++m_badSocketMessageCount;
347 std::lock_guard<std::shared_timed_mutex> lock(m_requestsMutex);
348 const auto range = m_requests.equal_range(
id.m_socket);
349 auto request = range.first;
350 while(request != range.second)
352 std::unique_lock<std::mutex> lock(
353 request->second->mutex,
358 request = m_requests.erase(request);
359 #if FASTCGIPP_LOG_LEVEL > 3 360 ++m_badSocketKillCount;
370 #if FASTCGIPP_LOG_LEVEL > 3 373 std::unique_lock<std::shared_timed_mutex> lock(m_requestsMutex);
374 auto request = m_requests.find(
id);
375 if(request == m_requests.end())
377 if(message.type == 0)
388 request = m_requests.emplace(
389 std::piecewise_construct,
390 std::forward_as_tuple(
id),
391 std::forward_as_tuple()).first;
393 request->second = makeRequest(
398 #if FASTCGIPP_LOG_LEVEL > 3 400 m_maxRequests = std::max(m_maxRequests, m_requests.size());
404 WARNING_LOG(
"Got a non BEGIN_REQUEST record for a request"\
405 " that doesn't exist")
410 request->second->push(std::move(message));
412 std::lock_guard<std::mutex> lock(m_tasksMutex);
421 DIAG_LOG(
"Manager_base::~Manager_base(): New requests ============== " \
423 DIAG_LOG(
"Manager_base::~Manager_base(): Max concurrent requests === " \
425 DIAG_LOG(
"Manager_base::~Manager_base(): Management records ======== " \
426 << m_managementRecordCount)
427 DIAG_LOG(
"Manager_base::~Manager_base(): Bad socket messages ======= " \
428 << m_badSocketMessageCount)
429 DIAG_LOG(
"Manager_base::~Manager_base(): Bad socket request kills == " \
430 << m_badSocketKillCount)
431 DIAG_LOG(
"Manager_base::~Manager_base(): Request messages received = " \
433 DIAG_LOG(
"Manager_base::~Manager_base(): Maximum active threads ==== " \
434 << m_maxActiveThreads)
435 DIAG_LOG(
"Manager_base::~Manager_base(): Remaining requests ======== " \
436 << m_requests.size())
437 DIAG_LOG(
"Manager_base::~Manager_base(): Remaining tasks =========== " \
439 DIAG_LOG(
"Manager_base::~Manager_base(): Remaining local messages == " \
440 << m_messages.size())
Topmost namespace for the fastcgi++ library.
RecordType type
Unknown record type.
const ManagementReply< 13, 2 > maxReqsReply
The maximum allowed requests at a time.
bool kill() const
Get keep alive value from the record body.
General task and protocol management class base.
bool processParamHeader(const char *data, const char *const dataEnd, const char *&name, const char *&value, const char *&end)
Process the body of a FastCGI record of type RecordType::PARAMS.
static void setupSignals()
Configure the handlers for POSIX signals.
void header(Level level)
Send a log header to logstream.
void handler()
General handling function to have it's own thread.
Data structure used to pass messages to requests.
const ManagementReply< 15, 1 > mpxsConnsReply
Where or not requests can be multiplexed over a single connections.
BigEndian< Role > role
Role.
void join()
Block until a stop() or terminate() is called and completed.
Declares the Manager class.
#define FASTCGIPP_LOG_LEVEL
const uint16_t badFcgiId
Constant that defines a bad/special FcgiId.
The body for FastCGI records with a RecordType of UNKNOWN_TYPE.
void start()
Call from any thread to start the Manager.
static void signalHandler(int signum)
General function to handler POSIX signals.
void localHandler()
Handles management messages.
Class for representing an OS level I/O socket.
A unique identifier for each FastCGI request.
void push(Protocol::RequestId id, Message &&message)
Pass a message to a request.
Block data
The raw data being passed along with the message.
The body for FastCGI records with a RecordType of BEGIN_REQUEST.
void terminate()
Call from any thread to terminate the Manager.
Manager_base(unsigned threads)
Sole constructor.
void stop()
Call from any thread to stop the Manager.
#define FAIL_LOG(data)
Log any "errors" that cannot be recovered from and then exit.
char * end()
Pointer to 1+ the last element.
static Manager_base * instance
Pointer to the Manager object.
#define ERROR_LOG(data)
Log any "errors" that can be recovered from.
Declares the Fastcgipp debugging/logging facilities.
const ManagementReply< 14, 2 > maxConnsReply
The maximum allowed file descriptors open at a time.
const int version
The version of the FastCGI protocol that this adheres to.
Data structure to hold a block of raw data.
int type
Type of message. A 0 means FastCGI record. Anything else is open.
#define WARNING_LOG(data)
Log any externally caused "errors".
char * begin()
Pointer to the first element.