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:
crs 2002-07-18 17:00:48 +00:00
parent 0759cbc104
commit 635c3d1c62
2 changed files with 30 additions and 9 deletions

View File

@ -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;

View File

@ -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;