now cancelling and waiting for the accept client thread before
cancelling any other threads. this prevents a race condition where we disconnect a client but it reconnects before we manage to shutdown. that might leave a thread running and the connection won't be closed down properly.
This commit is contained in:
parent
0759cbc104
commit
635c3d1c62
|
@ -29,6 +29,10 @@ const SInt32 CServer::s_httpMaxSimultaneousRequests = 3;
|
||||||
|
|
||||||
CServer::CServer(const CString& serverName) :
|
CServer::CServer(const CString& serverName) :
|
||||||
m_name(serverName),
|
m_name(serverName),
|
||||||
|
m_bindTimeout(5.0 * 60.0),
|
||||||
|
m_socketFactory(NULL),
|
||||||
|
m_securityFactory(NULL),
|
||||||
|
m_acceptClientThread(NULL),
|
||||||
m_active(NULL),
|
m_active(NULL),
|
||||||
m_primaryClient(NULL),
|
m_primaryClient(NULL),
|
||||||
m_seqNum(0),
|
m_seqNum(0),
|
||||||
|
@ -36,9 +40,7 @@ CServer::CServer(const CString& serverName) :
|
||||||
m_httpServer(NULL),
|
m_httpServer(NULL),
|
||||||
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests)
|
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests)
|
||||||
{
|
{
|
||||||
m_socketFactory = NULL;
|
// do nothing
|
||||||
m_securityFactory = NULL;
|
|
||||||
m_bindTimeout = 5.0 * 60.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CServer::~CServer()
|
CServer::~CServer()
|
||||||
|
@ -82,7 +84,9 @@ CServer::run()
|
||||||
log((CLOG_NOTE "starting server"));
|
log((CLOG_NOTE "starting server"));
|
||||||
|
|
||||||
// start listening for new clients
|
// start listening for new clients
|
||||||
startThread(new TMethodJob<CServer>(this, &CServer::acceptClients));
|
m_acceptClientThread = new CThread(startThread(
|
||||||
|
new TMethodJob<CServer>(this,
|
||||||
|
&CServer::acceptClients)));
|
||||||
|
|
||||||
// start listening for HTTP requests
|
// start listening for HTTP requests
|
||||||
if (m_config.getHTTPAddress().isValid()) {
|
if (m_config.getHTTPAddress().isValid()) {
|
||||||
|
@ -220,6 +224,7 @@ CServer::onError()
|
||||||
stopThreads(3.0);
|
stopThreads(3.0);
|
||||||
|
|
||||||
// done with the HTTP server
|
// done with the HTTP server
|
||||||
|
CLock lock(&m_mutex);
|
||||||
delete m_httpServer;
|
delete m_httpServer;
|
||||||
m_httpServer = NULL;
|
m_httpServer = NULL;
|
||||||
|
|
||||||
|
@ -1016,7 +1021,7 @@ CServer::closeClients(const CConfig& config)
|
||||||
reapThreads();
|
reapThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
CThread
|
||||||
CServer::startThread(IJob* job)
|
CServer::startThread(IJob* job)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
@ -1025,8 +1030,10 @@ CServer::startThread(IJob* job)
|
||||||
doReapThreads(m_threads);
|
doReapThreads(m_threads);
|
||||||
|
|
||||||
// add new thread to list. use the job as user data for logging.
|
// add new thread to list. use the job as user data for logging.
|
||||||
m_threads.push_back(CThread(job, job));
|
CThread thread(job, job);
|
||||||
log((CLOG_DEBUG1 "started thread %p", m_threads.back().getUserData()));
|
m_threads.push_back(thread);
|
||||||
|
log((CLOG_DEBUG1 "started thread %p", thread.getUserData()));
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1034,6 +1041,20 @@ CServer::stopThreads(double timeout)
|
||||||
{
|
{
|
||||||
log((CLOG_DEBUG1 "stopping threads"));
|
log((CLOG_DEBUG1 "stopping threads"));
|
||||||
|
|
||||||
|
// cancel the accept client thread to prevent more clients from
|
||||||
|
// connecting while we're shutting down.
|
||||||
|
CThread* acceptClientThread;
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
acceptClientThread = m_acceptClientThread;
|
||||||
|
m_acceptClientThread = NULL;
|
||||||
|
}
|
||||||
|
if (acceptClientThread != NULL) {
|
||||||
|
acceptClientThread->cancel();
|
||||||
|
acceptClientThread->wait(timeout);
|
||||||
|
delete acceptClientThread;
|
||||||
|
}
|
||||||
|
|
||||||
// close all clients (except the primary)
|
// close all clients (except the primary)
|
||||||
{
|
{
|
||||||
CConfig emptyConfig;
|
CConfig emptyConfig;
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
class CClientProxy;
|
class CClientProxy;
|
||||||
class CHTTPServer;
|
class CHTTPServer;
|
||||||
class CPrimaryClient;
|
class CPrimaryClient;
|
||||||
class CThread;
|
|
||||||
class IClient;
|
class IClient;
|
||||||
class IDataSocket;
|
class IDataSocket;
|
||||||
class IServerProtocol;
|
class IServerProtocol;
|
||||||
|
@ -118,7 +117,7 @@ private:
|
||||||
void closeClients(const CConfig& config);
|
void closeClients(const CConfig& config);
|
||||||
|
|
||||||
// start a thread, adding it to the list of threads
|
// start a thread, adding it to the list of threads
|
||||||
void startThread(IJob* adopted);
|
CThread startThread(IJob* adopted);
|
||||||
|
|
||||||
// cancel running threads, waiting at most timeout seconds for
|
// cancel running threads, waiting at most timeout seconds for
|
||||||
// them to finish.
|
// them to finish.
|
||||||
|
@ -171,6 +170,7 @@ private:
|
||||||
|
|
||||||
// running threads
|
// running threads
|
||||||
CThreadList m_threads;
|
CThreadList m_threads;
|
||||||
|
CThread* m_acceptClientThread;
|
||||||
|
|
||||||
// the screens
|
// the screens
|
||||||
typedef std::map<CString, IClient*> CClientList;
|
typedef std::map<CString, IClient*> CClientList;
|
||||||
|
|
Loading…
Reference in New Issue